Bash: proses substitusi dan stdin

13

Baris berikut jelas:

echo "bla" | foo | bar

Tetapi apakah yang di bawah melakukan hal yang sama?

echo "bla" | bar <(foo)
echo "bla" | bar < <(foo)

Manakah dari foodan barmembaca "bla" dari stdin dan mengapa?

Maksud saya, tentu saja, saya hanya bisa mengkodekannya dan memeriksanya, tapi saya tidak yakin apakah itu perilaku yang didefinisikan atau saya sedang mengeksploitasi fitur yang seharusnya tidak saya andalkan.

etam1024
sumber

Jawaban:

9

Itu tergantung shell dan tidak didokumentasikan AFAICS. Di kshdan bash, dalam kasus pertama, fooakan berbagi stdin yang sama dengan bar. Mereka akan berjuang untuk hasil echo.

Jadi misalnya di,

$ seq 10000 | paste - <(tr 1 X)'
1       X
2       X042
3       X043
4       X044
5       X045
[...]

Anda melihat bukti yang pastemembaca setiap blok teks lainnya dari seqoutput sementara trmembaca yang lain.

Dengan zsh, ia mendapat stdin luar (kecuali itu terminal dan shell tidak interaktif dalam hal ini diarahkan dari /dev/null). ksh(dari mana asalnya), zshdan bashmerupakan satu-satunya cangkang mirip Bourne dengan dukungan untuk proses substitusi AFAIK.

Dalam echo "bla" | bar < <(foo), perhatikan bahwa barstdin akan menjadi pipa yang diumpankan oleh keluaran dari foo. Itu perilaku yang didefinisikan dengan baik. Dalam hal ini, tampaknya foostdin adalah pipa yang diumpankan oleh echosemua ksh, zshdan bash.

Jika Anda ingin memiliki perilaku yang konsisten di ketiga shell dan menjadi bukti di masa depan karena perilaku mungkin berubah karena tidak didokumentasikan, saya akan menulis:

echo bla | { bar <(foo); }

Yang pasti foostdin juga merupakan pipa dari echo(saya tidak bisa melihat mengapa Anda ingin melakukan itu). Atau:

echo bla | bar <(foo < /dev/null)

Untuk memastikan footidak tidak membaca dari pipa dari echo. Atau:

{ echo bla | bar 3<&- <(foo <&3); } 3<&0

Untuk memiliki foostdin stdin luar seperti dalam versi saat ini zsh.

Stéphane Chazelas
sumber
"Dalam hal ini, stdin foo adalah pipa yang diumpankan oleh gema di semua ksh, zsh dan bash." Anda telah menguji ini dengan tangan sekarang, atau apakah di suatu tempat didokumentasikan?
etam1024
Apakah "dalam kasus pertama" pada baris pertama merujuk ke `| foo | bar` atau `| bar <(foo) `?
Volker Siegel
4

echo "bla" | foo | bar: Output dari echo "bla"diarahkan ke foo, yang output diarahkan ke bar.

echo "bla" | bar <(foo): Yang satu pipa output echo "bla"ke bar. Tetapi bardieksekusi dengan argumen. Argumennya adalah path ke file descritor, di mana output fooakan dikirim ke. Argumen ini berperilaku seperti file yang berisi output dari foo. Jadi, itu tidak sama.

echo "bla" | bar < <(foo): Seseorang dapat berasumsi bahwa output dari echo "bla"harus dikirim ke bardan seluruh pernyataan setara dengan yang pertama. Tapi itu tidak benar. Berikut ini terjadi: Karena pengalihan input <dilakukan setelah pipa ( |), itu menimpa itu . Jadi echo "bla"tidak disalurkan ke bar. Sebaliknya output foodiarahkan sebagai input standar untuk bar. Untuk menghapus ini lihat perintah dan keluaran berikut:

$ echo "bla" | cat < <(echo "foo")
foo

Seperti yang Anda lihat echo "bla"digantikan oleh echo "foo".

Sekarang lihat perintah ini:

$ echo "bar" | cat < <(awk '{printf "%s and foo", $0}')
bar and foo

Jadi echo "bar"disalurkan ke awk, yang membaca stdin dan menambahkan string and fooke output. Output ini disalurkan ke cat.

kekacauan
sumber
Dan pertanyaan saya adalah: "Apakah fakta yang awkmembaca" bar "adalah perilaku yang didefinisikan?"
etam1024
Ya itu. cmd1 < <(cmd2)berperilaku sama dengan cmd2 | cmd1.
chaos
Atau cmd1 | cmd2 | cmd3sama dengancmd1 | cmd3 < <(cmd2)
chaos
3
Jika itu wikipedia saya akan menaruh tag "rujukan?" Pada pernyataan Anda :) Inti dari pertanyaan saya adalah ia berfungsi seperti yang Anda katakan, tetapi saya tidak dapat menemukan dokumentasi tentang hal itu.
etam1024