Apa sebenarnya <() dalam bash (dan = () dalam zsh)?

36

Saya cukup nyaman dengan bash, tetapi baru-baru ini saya berakhir dengan substitusi yang saya tidak tahu.

Apa sebenarnya yang ada <(<command>)di bash? Bagaimana cara membandingkannya dengan =(<command>)in zsh?

Saya mengerti bahwa ini ada hubungannya dengan deskriptor file default. Di komputer saya

echo <()

kembali /proc/self/fd/11, yang saya temukan sebagai salinan skrip STDOUT, tetapi ini masih tampak cukup membingungkan bagi saya.

Henrique Barcelos
sumber

Jawaban:

51

Ini disebut proses substitusi.

The <(list)sintaks didukung oleh keduanya, bashdan zsh. Ini memberikan cara untuk melewatkan output dari perintah ( list) ke perintah lain saat menggunakan pipa ( |) tidak mungkin. Misalnya ketika sebuah perintah tidak mendukung input dari STDINatau Anda memerlukan output dari beberapa perintah:

diff <(ls dirA) <(ls dirB)

<(list)menghubungkan output listdengan file dalam /dev/fd, jika didukung oleh sistem, jika tidak pipa bernama (FIFO) digunakan (yang juga tergantung pada dukungan oleh sistem; tidak ada manual yang mengatakan apa yang terjadi jika kedua mekanisme tidak didukung, mungkin dibatalkan dengan kesalahan). Nama file kemudian dilewatkan sebagai argumen pada baris perintah.


zshtambahan mendukung =(list)penggantian mungkin untuk <(list). Dengan =(list)file sementara digunakan bukan file dalam /dev/fdatau FIFO. Ini dapat digunakan sebagai pengganti <(list)jika program perlu melihat dalam output.

Menurut manual ZSH mungkin juga ada masalah lain dengan cara <(list)kerjanya:

The =Bentuk berguna baik sebagai /dev/fddan implementasi pipa bernama <(...)memiliki kelemahan. Dalam kasus sebelumnya, beberapa program dapat secara otomatis menutup deskriptor file yang bersangkutan sebelum memeriksa file pada baris perintah, terutama jika ini diperlukan untuk alasan keamanan seperti ketika program sedang menjalankan setuid. Dalam kasus kedua, jika program tidak benar-benar membuka file, subshell yang mencoba membaca atau menulis ke pipa akan (dalam implementasi yang khas, sistem operasi yang berbeda mungkin memiliki perilaku yang berbeda) blok untuk selamanya dan harus dibunuh secara eksplisit . Dalam kedua kasus, shell benar-benar memasok informasi menggunakan pipa, sehingga program yang berharap untuk melihat (lihat halaman manual lseek(2)) pada file tidak akan berfungsi.

Adaephon
sumber
Ini membantu saya mencari tahu mengapa MacOS pfctl -f <(echo "pf rules")akan mengatakan deskriptor file yang buruk. menggunakan zsh dan = (echo "pf rules") sebagai gantinya berfungsi.
johnnyB
9

Catatan, ini adalah jawaban bash, bukan zsh.

Ada kasus di bash di mana Anda tidak dapat menggunakan pipa:

some_command | some_other_command

karena pipa memperkenalkan subkulit untuk setiap komponen pipa, ketika subkulit keluar, efek samping apa pun yang Anda andalkan akan hilang. Misalnya, contoh buat ini:

cat file | while read line; do ((count++)); done
echo $count

akan menampilkan baris kosong, karena $countvariabel tidak ada di shell saat ini.

Substitusi proses bash memungkinkan Anda menghindari teka-teki ini dengan memungkinkan Anda membaca dari output "some_command" seperti yang Anda lakukan dari file

while read line; do ((count++)); done < <(cat file)
# ....................................1.2
echo $count   # the variable *does* exist in the current shell

(1) adalah pengalihan input normal. (2) adalah awal dari <()proses subtitusi sintaksis.

glenn jackman
sumber
2
= (cmdlist) di zsh memiliki efek yang hampir sama dengan <(cmdlist) di bash tetapi ia membuat (dan menghapus saat siap) file sementara dengan output cmdlist untuk pengalihan. Ini bagus ketika pencarian berpotensi dilakukan dalam program. <(cmdlist) juga dikenal oleh zsh.
Gombai Sándor