GNU/Linux >> Belajar Linux >  >> Linux

Proses Substitusi Output Out Of The Order?

echo one; echo two > >(cat); echo three; 

perintah memberikan keluaran yang tidak diharapkan.

Saya membaca ini:Bagaimana proses substitusi diimplementasikan di bash? dan banyak artikel lain tentang proses substitusi di internet, tetapi tidak mengerti mengapa ia berperilaku seperti ini.

Keluaran yang diharapkan:

one
two
three

Keluaran nyata:

prompt$ echo one; echo two > >(cat); echo three;
one
three
prompt$ two

Juga, dua perintah ini harus setara dari sudut pandang saya, tetapi tidak:

##### first command - the pipe is used.
prompt$ seq 1 5 | cat
1
2
3
4
5
##### second command - the process substitution and redirection are used.
prompt$ seq 1 5 > >(cat)
prompt$ 1
2
3
4
5

Mengapa saya pikir, mereka harus sama? Karena, keduanya menghubungkan seq output ke cat masukan melalui pipa anonim – Wikipedia, Substitusi proses.

Pertanyaan: Mengapa berperilaku seperti ini? Di mana kesalahan saya? Jawaban yang komprehensif diinginkan (dengan penjelasan tentang bagaimana bash melakukannya di bawah tenda).

Jawaban yang Diterima:

Ya, di bash seperti di ksh (dari mana fitur tersebut berasal), proses di dalam proses substitusi tidak menunggu (sebelum menjalankan perintah berikutnya dalam skrip).

untuk <(...) satu, itu biasanya baik-baik saja seperti di:

cmd1 <(cmd2)

shell akan menunggu cmd1 dan cmd1 biasanya akan menunggu cmd2 berdasarkan itu membaca sampai akhir file pada pipa yang diganti, dan akhir file itu biasanya terjadi ketika cmd2 mati. Itulah alasan yang sama beberapa shell (bukan bash ) jangan repot-repot menunggu cmd2 di cmd2 | cmd1 .

Untuk cmd1 >(cmd2) , namun, umumnya tidak demikian, karena lebih dari cmd2 yang biasanya menunggu cmd1 di sana jadi biasanya akan keluar setelahnya.

Itu diperbaiki di zsh yang menunggu cmd2 di sana (tetapi tidak jika Anda menulisnya sebagai cmd1 > >(cmd2) dan cmd1 tidak terpasang, gunakan {cmd1} > >(cmd2) sebagai gantinya seperti yang didokumentasikan).

ksh tidak menunggu secara default, tetapi memungkinkan Anda menunggu dengan wait builtin (itu juga membuat pid tersedia di $! , meskipun itu tidak membantu jika Anda melakukan cmd1 >(cmd2) >(cmd3) )

rc (dengan cmd1 >{cmd2} sintaks), sama seperti ksh kecuali Anda bisa mendapatkan pid dari semua proses latar belakang dengan $apids .

es (juga dengan cmd1 >{cmd2} ) menunggu cmd2 seperti di zsh , dan juga menunggu cmd2 di <{cmd2} proses pengalihan.

bash memang membuat pid dari cmd2 (atau lebih tepatnya subkulit seperti yang dijalankan cmd2 dalam proses anak dari subkulit itu meskipun itu adalah perintah terakhir di sana) tersedia di $! , tetapi tidak membuat Anda menunggu.

Jika Anda harus menggunakan bash , Anda dapat mengatasi masalah tersebut dengan menggunakan perintah yang akan menunggu kedua perintah dengan:

{ { cmd1 >(cmd2); } 3>&1 >&4 4>&- | cat; } 4>&1

Itu membuat keduanya cmd1 dan cmd2 memiliki fd 3 mereka terbuka ke pipa. cat akan menunggu akhir file di ujung yang lain, jadi biasanya hanya akan keluar ketika keduanya cmd1 dan cmd2 telah mati. Dan shell akan menunggu cat itu memerintah. Anda dapat melihatnya 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 memiliki latar belakang sendiri asalkan mereka tidak menutup semua deskriptor file mereka seperti yang biasanya dilakukan daemon).

Terkait:Apa yang menyebabkan file kehilangan izin?

Perhatikan bahwa berkat proses subkulit yang terbuang yang disebutkan di atas, ini berfungsi bahkan jika cmd2 menutup fd 3-nya (perintah biasanya tidak melakukan itu, tetapi beberapa seperti sudo atau ssh melakukan). Versi bash yang akan datang akhirnya dapat melakukan optimasi di sana seperti di shell lainnya. Maka Anda memerlukan sesuatu seperti:

{ { cmd1 >(sudo cmd2; exit); } 3>&1 >&4 4>&- | cat; } 4>&1

Untuk memastikan masih ada proses shell ekstra dengan fd 3 terbuka menunggu sudo itu perintah.

Perhatikan bahwa cat tidak akan membaca apa pun (karena proses tidak menulis di fd 3). Itu hanya ada untuk sinkronisasi. Itu hanya akan melakukan satu read() panggilan sistem yang akan kembali tanpa hasil.

Anda sebenarnya dapat menghindari menjalankan cat dengan menggunakan substitusi perintah untuk melakukan sinkronisasi pipa:

{ unused=$( { cmd1 >(cmd2); } 3>&1 >&4 4>&-); } 4>&1

Kali ini cangkangnya bukan cat yaitu membaca dari pipa yang ujung lainnya terbuka pada fd 3 dari cmd1 dan cmd2 . Kami menggunakan penugasan variabel sehingga status keluar dari cmd1 tersedia di $? .

Atau Anda dapat melakukan proses substitusi dengan tangan, dan kemudian Anda bahkan dapat menggunakan sh . sistem Anda karena itu akan menjadi sintaks shell standar:

{ cmd1 /dev/fd/3 3>&1 >&4 4>&- | cmd2 4>&-; } 4>&1

meskipun perhatikan seperti yang disebutkan sebelumnya bahwa tidak semua sh implementasi akan menunggu cmd1 setelah cmd2 telah selesai (meskipun itu lebih baik daripada sebaliknya). Waktu itu, $? berisi status keluar dari cmd2; meskipun bash dan zsh buat cmd1 status keluar tersedia di ${PIPESTATUS[0]} dan $pipestatus[1] masing-masing (lihat juga pipefail opsi dalam beberapa shell jadi $? dapat melaporkan kegagalan komponen pipa selain yang terakhir)

Perhatikan bahwa yash memiliki masalah serupa dengan proses pengalihan fitur. cmd1 >(cmd2) akan ditulis cmd1 /dev/fd/3 3>(cmd2) di sana. Tapi cmd2 tidak menunggu dan Anda tidak dapat menggunakan wait untuk menunggunya juga dan pidnya tidak tersedia di $! variabel baik. Anda akan menggunakan pekerjaan yang sama seperti untuk bash .


Linux
  1. Proses Induk Baru Ketika Proses Induk Meninggal?

  2. Apa Yang Terjadi Dengan Keluaran Dari Proses Yang Telah Diabaikan Dan Kehilangan Terminalnya?

  3. Output Dari Perintah "terakhir"?

  1. Bagaimana Mengubah Pengalihan Output Dari Proses yang Berjalan?

  2. Nilai Maksimum Id Proses?

  3. Apa Artinya Dalam Keluaran Dari Ps?

  1. Diff Dimana Garis Hampir Sama Tapi Rusak?

  2. Jalankan proses dengan output realtime di PHP

  3. Linux:cari tahu proses apa yang menggunakan semua RAM?