Apa perbedaan antara && dan | dalam skrip bash?


12

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?


@ heemayl Terima kasih. Bisakah Anda mengekstrak perbedaan pada kasus saya? Terima kasih.
Nam G VU

1
Petunjuk: Perintah di kedua sisi |dijalankan dalam subkulit.
heemayl

Jawaban:


21

Dalam p=$(cd ~ && pwd):

  • Substitusi perintah $(),, berjalan dalam subkulit

  • cd ~mengubah direktori menjadi ~(rumah Anda), jika cdberhasil ( &&) kemudian pwdmencetak nama direktori pada STDOUT, maka string yang disimpan di pakan 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 pwddalam subkulit terpisah

  • jadi Anda hanya akan mendapatkan STDOUT dari pwdyaitu dari mana Anda menjalankan perintah, ini bisa berupa direktori seperti yang Anda bayangkan, maka pakan berisi nama direktori dari mana perintah dipanggil, bukan direktori home Anda


Apa tujuan dari pipa di antara perintah? cd ~tidak menghasilkan output apa pun, dan pwdtidak membaca input apa pun.
Barmar

Perintah kedua pada dasarnya setara dengan (cd ~);p=$(pwd)bukan?
Barmar

@Barmar Ya, itulah yang digunakan OP, dan saya hanya menjelaskannya untuknya.
heemayl

6

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
~$ 
  • Perintah cd ~mengubah "direktori sekarang" ke rumah dari pengguna aktual yang menjalankan perintah ( /home/user).
  • Karena hasil dari perintah berhasil (kode keluar 0), perintah berikutnya setelah && dijalankan
  • Dan "direktori kerja sekarang" dicetak.
  • Shell yang berjalan telah berubah pwdmenjadi ~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 falsemencegah 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.

  • The cd ~mengubah pwd dari satu shell.
  • The pwdmencetak (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.


5

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 command2hanya akan dieksekusi ketika command1telah menyelesaikan dan mengembalikan kode hasil yang sukses. Jika Anda command1 || command2 command2akan dieksekusi ketika command1selesai jika command1mengembalikan kode kegagalan.

Paradigma umum lainnya adalah memiliki command1perintah 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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.