Ya, bashseperti di ksh( di mana fitur tersebut berasal), proses di dalam proses substitusi tidak menunggu (sebelum menjalankan perintah berikutnya dalam skrip).
untuk <(...)satu, itu biasanya baik seperti di:
cmd1 <(cmd2)
shell akan menunggu cmd1dan cmd1biasanya akan menunggu cmd2berdasarkan pembacaan sampai akhir file pada pipa yang diganti, dan bahwa end-file biasanya terjadi ketika cmd2mati. Itulah alasan yang sama mengapa beberapa kerang (tidak bash) tidak perlu menunggu untuk cmd2masuk cmd2 | cmd1.
Untuk cmd1 >(cmd2), bagaimanapun, bahwa umumnya tidak terjadi, karena lebih cmd2yang biasanya menunggu cmd1di sana sehingga umumnya akan keluar setelah.
Itu sudah diperbaiki zshyang menunggu di cmd2sana (tetapi tidak jika Anda menuliskannya sebagai cmd1 > >(cmd2)dan cmd1bukan bawaan, gunakan {cmd1} > >(cmd2)sebagai gantinya yang didokumentasikan ).
kshtidak menunggu secara default, tetapi memungkinkan Anda menunggu dengan waitbuiltin (itu juga membuat pid tersedia $!, meskipun itu tidak membantu jika Anda melakukannya cmd1 >(cmd2) >(cmd3))
rc(dengan cmd1 >{cmd2}sintaks), sama seperti kshkecuali Anda bisa mendapatkan semua proses latar belakang dengan $apids.
es(juga dengan cmd1 >{cmd2}) menunggu cmd2like in zsh, dan juga menunggu redirections cmd2dalam <{cmd2}proses.
bashmemang membuat pid dari cmd2(atau lebih tepatnya dari subkulit seperti itu berjalan cmd2dalam proses anak dari subkulit itu meskipun itu adalah perintah terakhir di sana) tersedia di $!, tetapi tidak membiarkan Anda menunggu untuk itu.
Jika Anda harus menggunakan bash, Anda dapat mengatasi masalah dengan menggunakan perintah yang akan menunggu kedua perintah dengan:
{ { cmd1 >(cmd2); } 3>&1 >&4 4>&- | cat; } 4>&1
Itu membuat keduanya cmd1dan cmd2memiliki fd 3 terbuka untuk sebuah pipa. catakan menunggu akhir file di ujung yang lain, jadi biasanya hanya akan keluar ketika keduanya cmd1dan cmd2sudah mati. Dan shell akan menunggu catperintah itu. Anda dapat melihat bahwa sebagai jaring untuk menangkap penghentian semua proses latar belakang (Anda dapat menggunakannya untuk hal-hal lain yang dimulai di latar belakang seperti dengan &, coprocs atau bahkan perintah yang melatarbelakangi diri mereka sendiri asalkan mereka tidak menutup semua deskriptor file mereka seperti yang biasanya dilakukan daemon ).
Perhatikan bahwa berkat proses subkulit sia-sia yang disebutkan di atas, ia bekerja bahkan jika cmd2menutup fd 3-nya (perintah biasanya tidak melakukan itu, tetapi beberapa suka sudoatau sshtidak). Versi masa depan pada bashakhirnya dapat melakukan optimasi di sana seperti di shell lain. Maka Anda akan membutuhkan sesuatu seperti:
{ { cmd1 >(sudo cmd2; exit); } 3>&1 >&4 4>&- | cat; } 4>&1
Untuk memastikan masih ada proses shell tambahan dengan fd 3 yang terbuka menunggu sudoperintah itu.
Catatan yang cattidak akan membaca apa pun (karena proses tidak menulis di fd 3 mereka). Itu hanya ada untuk sinkronisasi. Ini akan melakukan hanya satu read()panggilan sistem yang akan kembali tanpa hasil di akhir.
Anda sebenarnya dapat menghindari berjalan catdengan menggunakan substitusi perintah untuk melakukan sinkronisasi pipa:
{ unused=$( { cmd1 >(cmd2); } 3>&1 >&4 4>&-); } 4>&1
Kali ini, itu shell bukan catyang membaca dari pipa yang ujungnya terbuka pada fd 3 dari cmd1dan cmd2. Kami menggunakan tugas variabel sehingga status keluar dari cmd1tersedia di $?.
Atau Anda bisa melakukan proses substitusi dengan tangan, dan kemudian Anda bahkan bisa menggunakan sistem Anda shkarena itu akan menjadi sintaksis shell standar:
{ cmd1 /dev/fd/3 3>&1 >&4 4>&- | cmd2 4>&-; } 4>&1
meskipun perhatikan seperti disebutkan sebelumnya bahwa tidak semua sh implementasi akan menunggu cmd1setelah cmd2selesai (meskipun itu lebih baik daripada sebaliknya). Waktu itu, $?berisi status keluar dari cmd2; meskipun bashdan zshmembuat cmd1status keluar tersedia di ${PIPESTATUS[0]}dan $pipestatus[1]masing - masing (lihat juga pipefailopsi dalam beberapa shell sehingga $?dapat melaporkan kegagalan komponen pipa selain yang terakhir)
Catatan yang yashmemiliki masalah serupa dengan fitur pengalihan prosesnya .cmd1 >(cmd2)akan ditulis di cmd1 /dev/fd/3 3>(cmd2)sana. Tetapi cmd2tidak menunggu dan Anda tidak dapat menggunakannya waituntuk menunggu dan pidnya tidak tersedia dalam $!variabel juga. Anda akan menggunakan pekerjaan yang sama untuk bash.