Mari kita ambil dua baris di bawah ini yang memberi kita dua hasil berbeda.
p=$(cd ~ && pwd) ; echo $p
p=$(cd ~ | pwd) ; echo $p
Bagaimana keduanya berbeda?
|
dijalankan dalam subkulit.
Mari kita ambil dua baris di bawah ini yang memberi kita dua hasil berbeda.
p=$(cd ~ && pwd) ; echo $p
p=$(cd ~ | pwd) ; echo $p
Bagaimana keduanya berbeda?
|
dijalankan dalam subkulit.
Jawaban:
Dalam p=$(cd ~ && pwd)
:
Substitusi perintah $()
,, berjalan dalam subkulit
cd ~
mengubah direktori menjadi ~
(rumah Anda), jika cd
berhasil ( &&
) kemudian pwd
mencetak nama direktori pada STDOUT, maka string yang disimpan di p
akan menjadi direktori home Anda misalnya/home/foobar
Dalam p=$(cd ~ | pwd)
:
Sekali lagi $()
memunculkan subkulit
Perintah di kedua sisi |
run di subshell masing-masing (dan keduanya dimulai pada saat yang sama)
begitu cd ~
juga dilakukan dalam subkulit, dan pwd
dalam subkulit terpisah
jadi Anda hanya akan mendapatkan STDOUT dari pwd
yaitu dari mana Anda menjalankan perintah, ini bisa berupa direktori seperti yang Anda bayangkan, maka p
akan berisi nama direktori dari mana perintah dipanggil, bukan direktori home Anda
cd ~
tidak menghasilkan output apa pun, dan pwd
tidak membaca input apa pun.
(cd ~);p=$(pwd)
bukan?
Masalah intinya adalah bagaimana operator &&
dan |
menghubungkan kedua perintah tersebut.
The &&
menghubungkan perintah melalui kode keluar. The |
menghubungkan dua perintah melalui file descriptor (stdin, stdout).
Ayo sederhanakan dulu. Kami dapat menghapus tugas dan menulis:
echo $(cd ~ && pwd)
echo $(cd ~ | pwd)
Kami bahkan dapat menghapus sub-shell eksekusi perintah untuk menganalisis ini:
$ cd ~ && pwd
$ cd ~ | pwd
Jika kami mengubah prompt untuk menampilkan direktori tempat perintah dijalankan, sesuatu seperti PS1='\w\$ '
, kita akan melihat ini:
/tmp/user$ cd ~ && pwd
/home/user
~$
cd ~
mengubah "direktori sekarang" ke rumah dari pengguna aktual yang menjalankan perintah ( /home/user
).pwd
menjadi ~
seperti yang ditunjukkan oleh prompt ~$
.Jika perubahan direktori tidak berhasil (kode keluar bukan 0) karena beberapa alasan (direktori tidak ada, izin memblokir membaca direktori) perintah selanjutnya tidak akan dieksekusi.
Contoh:
/tmp/user$ false && pwd
/tmp/user$ _
Kode keluar dari 1 false
mencegah eksekusi perintah selanjutnya.
Dengan demikian, kode keluar dari "perintah 1" adalah yang mempengaruhi "perintah 2".
Sekarang, efek dari seluruh perintah:
/tmp/user$ echo $(cd ~ && pwd)
/home/user
/tmp/user$ _
Direktori diubah, tetapi di dalam sub-shell $(…)
, direktori yang diubah dicetak /home/user
, tetapi segera dibuang ketika sub-shell ditutup. PWD kembali menjadi direktori awal ( /tmp/user
).
Inilah yang terjadi:
/tmp/user$ cd ~ | pwd
/tmp/user
/tmp/user$ _
Meta-karakter |
(bukan operator sejati) memberi sinyal shell untuk membuat apa yang disebut "Pipa", (dalam bash) setiap perintah di setiap sisi pipa ( |
) diatur di dalam masing-masing sub-shell sendiri, pertama sisi kanan perintah, maka, yang kiri. Deskriptor file input ( /dev/stdin
) dari perintah kanan terhubung ke deskriptor output ( /dev/stdout
) dan kemudian kedua perintah dimulai dan dibiarkan berinteraksi. Perintah kiri ( cd -
) tidak memiliki keluaran, dan, juga, perintah kanan ( pwd
) tidak menerima input. Jadi, masing-masing berjalan secara independen di dalam masing-masing sub-shell.
cd ~
mengubah pwd dari satu shell.pwd
mencetak (benar-benar independen) pwd dari sub-shell lainnya.Perubahan pada masing-masing shell dibuang ketika pipa berakhir, sub-shell eksternal belum mengubah pwd.
Itu sebabnya kedua perintah hanya dihubungkan oleh "file deskriptor".
Dalam hal ini, tidak ada yang dikirim, dan tidak ada yang dibaca.
Seluruh perintah:
$ echo "$(cd ~ | pwd)"
Hanya akan mencetak direktori tempat perintah itu dijalankan.
Saya tidak yakin apakah maksud Anda '|' atau '||' dalam kasus kedua Anda.
'|' dalam sebuah shell, output dari satu perintah ke input yang lain - kasus penggunaan umum adalah sesuatu seperti:
curl http://abcd.com/efgh | grep ijkl
yaitu menjalankan perintah, dan menggunakan perintah lain untuk memproses output dari suatu perintah.
Pada contoh yang Anda berikan, ini cukup tidak masuk akal, karena 'cd' biasanya tidak menghasilkan output apa pun, dan 'pwd' tidak mengharapkan input apa pun.
'&&' dan '||' adalah perintah mitra. Mereka dirancang untuk digunakan dengan cara yang sama dengan operator yang logis "dan" dan "atau" dalam sebagian besar bahasa. Namun, optimisasi yang dilakukan memberi mereka perilaku spesifik yaitu paradigma pemrograman shell.
Untuk menentukan hasil operasi logis "dan", Anda hanya perlu mengevaluasi kondisi kedua jika kondisi pertama berhasil - jika kondisi pertama gagal, hasil keseluruhan akan selalu salah.
Untuk menentukan hasil operasi "atau" logis, Anda hanya perlu mengevaluasi kondisi kedua jika kondisi pertama gagal - jika kondisi pertama berhasil, hasil keseluruhan akan selalu benar.
Jadi, di shell, jika Anda command1 && command2
command2
hanya akan dieksekusi ketika command1
telah menyelesaikan dan mengembalikan kode hasil yang sukses. Jika Anda command1 || command2
command2
akan dieksekusi ketika command1
selesai jika command1
mengembalikan kode kegagalan.
Paradigma umum lainnya adalah memiliki command1
perintah uji - ini menghasilkan satu baris jika / kemudian pernyataan - misalnya:
[ "$VAR" = "" ] && VAR="Value if empty"
Adalah cara (panjang lebar) dalam memberikan nilai ke variabel jika saat ini kosong.
Ada banyak contoh penggunaan proses ini di tempat lain di Stack Exchange