Mengapa saya tidak bisa mengalihkan keluaran nama jalur dari satu perintah ke "cd"?

27

Saya mencoba untuk cdmenerima nama direktori yang dialihkan ke sana dari perintah lain. Tidak satu pun dari metode ini yang berfungsi:

$ echo $HOME | cd
$ echo $HOME | xargs cd

Ini berhasil:

$ cd $(echo $HOME)

Mengapa set perintah pertama tidak berfungsi, dan adakah yang lain juga gagal dengan cara ini?

Jhonathan
sumber
Oleh orang lain apakah Anda merujuk ke perintah lain atau metode lain untuk menggunakan cd yang gagal dengan cara ini?
Didi Kohen
@ Davidvidohen saya merujuk ke perintah lain
Jhonathan
Beberapa contoh penting adalah ulimit, umask, popd, pushd, set, ekspor dan baca.
Didi Kohen

Jawaban:

32

cdbukan perintah eksternal - ini adalah fungsi shell builtin. Ini berjalan dalam konteks shell saat ini, dan tidak, seperti yang dilakukan perintah eksternal, dalam konteks fork / exec'd sebagai proses yang terpisah.

Contoh ketiga Anda berfungsi, karena shell memperluas variabel dan substitusi perintah sebelum memanggil cdbuiltin, sehingga cdmenerima nilai ${HOME}sebagai argumennya.

Sistem POSIX memang memiliki biner cd- pada mesin FreeBSD saya, itu ada /usr/bin/cd, tetapi tidak melakukan apa yang Anda pikirkan. Memanggil biner cdmenyebabkan shell untuk garpu / exec biner, yang memang mengubah direktori kerjanya menjadi nama yang Anda berikan. Namun, segera setelah itu terjadi, biner keluar, dan proses bercabang / exec menghilang, mengembalikan Anda ke shell Anda, yang masih dalam direktori itu sebelum Anda mulai.

D_Bye
sumber
10
Yang membuat orang bertanya-tanya Apa gunanya cdperintah eksternal ?
kojiro
23

cdtidak membaca input standar. Itu sebabnya contoh pertama Anda tidak berfungsi.

xargsmembutuhkan nama perintah, yaitu nama yang dapat dieksekusi secara independen. cdharus berupa perintah bawaan shell dan tidak akan memiliki efek (selain memverifikasi bahwa Anda dapat mengubah ke direktori itu dan efek samping potensial yang mungkin terjadi pada direktori automountable) jika itu adalah executable. Itulah sebabnya contoh kedua Anda tidak berhasil.

mouviciel
sumber
4

Selain jawaban yang baik yang sudah ada, perlu juga disebutkan bahwa sebuah pipa melakukan proses baru, yang memiliki direktori kerja tersendiri. Karenanya, mencoba melakukan ini, tidak akan berhasil:

echo test | cd /

Dengan demikian, Anda tidak akan berada di folder / setelah shell kembali dari perintah ini.

Mark Rejhon
sumber
Semua perintah dalam pipa berjalan dalam proses yang berbeda, jadi dalam a | b, bahkan jika adan bdibangun, setidaknya satu maka tidak berjalan dalam proses shell, tetapi tidak ada jaminan yang mana itu. Misalnya dalam AT&T ksh, zshatau bash -O lastpipe, bdijalankan dalam proses shell saat ini, sehingga kode Anda akan membawa Anda ke / di sana.
Stéphane Chazelas
4

Selain jawaban yang benar sudah diberikan: Jika Anda menjalankan bash dan ingin mencari tahu apa "perintah" seperti cd Anda dapat menggunakan tipe

$ type cd
cd is a shell builtin

atau mengapa tidak:

$ type time
time is a shell keyword

sementara misalnya waktu gnu biasanya sudah termasuk dalam distribusi favorit Anda:

$ which time
/usr/bin/time

Okey okey Anda mendapatkan ide, lalu apa jenisnya?

$ type type
type is a shell builtin

Berikut cuplikan manual bash:

       type [-aftpP] name [name ...]
          With no options, indicate how each name would be interpreted  if  used  as  a
          command name.  If the -t option is used, type prints a string which is one of
          alias, keyword, function, builtin,  or  file  if  name  is  an  alias,  shell
          reserved word, function, builtin, or disk file, respectively.  If the name is
          not found, then nothing is printed, and an exit status of false is  returned.
          If  the -p option is used, type either returns the name of the disk file that
          would be executed if name were specified as a command  name,  or  nothing  if
          ‘‘type  -t  name’’ would not return file.  The -P option forces a PATH search
          for each name, even if ‘‘type -t name’’ would not return file.  If a  command
          is  hashed,  -p  and -P print the hashed value, not necessarily the file that
          appears first in PATH.  If the -a option is used,  type  prints  all  of  the
          places  that  contain  an  executable  named name.  This includes aliases and
          functions, if and only if the -p option is  not  also  used.   The  table  of
          hashed  commands  is  not  consulted when using -a.  The -f option suppresses
          shell function lookup, as with the command builtin.  type returns true if any
          of the arguments are found, false if none are found.
3 bulan
sumber
0

Seperti yang orang lain katakan, itu tidak akan berfungsi karena cdini adalah perintah shell builtin, bukan program eksternal, sehingga tidak memiliki input standar yang dapat Anda gunakan untuk memasukkan apa pun.

Tetapi, bahkan jika itu berhasil, itu tidak akan melakukan apa yang Anda inginkan: sebuah pipa menumbuhkan proses baru dan mengarahkan output standar dari perintah pertama ke input standar dari yang kedua, sehingga hanya proses baru yang akan mengubah kerjanya saat ini direktori; ini tidak dapat memengaruhi proses pertama dengan cara apa pun.

Massimo
sumber
2
Paragraf kedua Anda benar. Tetapi ulangi paragraf pertama: mengapa Anda menganggap bahwa shell builtin tidak memiliki stdin? readbiasanya (selalu?) shell builtin. Memang benar bahwa cdmengabaikan stdin, tetapi ini bukan karena itu adalah builtin.
dubiousjim
-2

Opsi lain adalah backticks, yang menempatkan stdout dari satu perintah sebagai argumen baris perintah dari perintah kedua, dan lebih portabel daripada $(...). Sebagai contoh:

cd `echo $HOME`

atau lebih umum;

cd `anycommand -and whatever args`

Perhatikan bahwa penggunaan backticks tergantung pada shell untuk mengeksekusi perintah dan mengganti output pada baris perintah. Kebanyakan kerang mendukungnya.

Seth Noble
sumber
3
OP sudah menyatakan, dalam pertanyaannya, itu $(...)bekerja. Saya tidak berpikir itu saran yang baik untuk merekomendasikan backticks sebagai gantinya, karena mereka memiliki aturan mengutip yang jauh lebih rumit dan umumnya lebih rentan kesalahan. (Lihat §3.5.4 "Pergantian Perintah" dalam Manual Referensi Bash .)
ruakh
$ () bagus jika didukung, tetapi backticks lebih banyak didukung di berbagai shell dan sistem. Tetapi saya harus menguraikan kembali ini sebagai "pilihan lain".
Seth Noble
Kerang yang berbeda, ya; tetapi berbeda "sistem"? Apakah benar-benar ada cangkang yang mendukung $(...)pada satu sistem tetapi tidak pada yang lain ??
ruakh
4
-1, itu tidak menjawab pertanyaan sama sekali.
Bernhard
3
@ruakh & Seth: Semua dukungan POSIX shells $(…). Sistem tanpa shell POSIX (yaitu dengan shell Bourne asli) akan sangat tua. Bahkan sistem di mana /bin/shshell Bourne dan Anda memerlukan jalur lain seperti /usr/xpg4/bin/shuntuk mendapatkan shell POSIX jarang terjadi saat ini. Merekomendasikan backticks kepada siapa pun yang tidak mengelola unix boxen kuno secara profesional adalah merugikan mereka.
Gilles 'SANGAT berhenti menjadi jahat'