Pipa semi-sinkron


11

Asumsikan saya memiliki pipa berikut:

a | b | c | d

Bagaimana saya bisa menunggu selesainya c(atau b) di shatau bash? Ini berarti bahwa skrip ddapat mulai kapan saja (dan tidak perlu ditunggu-tunggu) tetapi membutuhkan hasil lengkap cuntuk bekerja dengan benar.

Case use adalah difftooluntuk gityang membandingkan gambar. Ini dipanggil oleh gitdan perlu memproses inputnya ( a | b | cbagian) dan menampilkan hasil perbandingan ( dbagian). Penelepon akan menghapus input yang diperlukan untuk adan b. Ini berarti bahwa sebelum kembali dari skrip, proses c(atau b) harus diakhiri. Di sisi lain, saya tidak bisa menunggu dkarena ini berarti saya sedang menunggu input pengguna.

Saya tahu saya bisa menulis hasil cke file sementara, atau mungkin menggunakan FIFO di bash. (Namun, tidak yakin apakah FIFO akan membantu.) Apakah mungkin untuk mencapai ini tanpa file sementara sh?

EDIT

Mungkin akan cukup jika saya bisa mengetahui ID proses dari c(atau b) proses dengan cara yang dapat diandalkan. Kemudian seluruh pipa dapat dimulai secara tidak sinkron, dan saya bisa menunggu proses ID. Sesuatu di sepanjang garis

wait $(a | b | { c & [print PID of c] ; } | d)

EDIT ^ 2

Saya telah menemukan solusi, komentar (atau solusi yang masih lebih baik) dipersilakan.


Maksud Anda, Anda ingin dmulai memproses coutput hanya setelah cselesai? Anda tidak ingin dmulai memproses setiap jalur keluaran saat datang?
terdon

@terdon: Tidak, dgratis untuk memulai kapan saja suka, tetapi charus selesai sebelum saya bisa melanjutkan.
krlmlr

Itu tampaknya kontradiktif dengan diri sendiri, jika dbisa dimulai ketika suka, apa yang sebenarnya Anda tunggu?
terdon

@terdon: Diperluas untuk menampilkan use case.
krlmlr

Jika dtidak menggunakan output cmaka sepertinya tidak masuk akal untuk membuat dbagian dari pipa. Tetapi jika dmemang menggunakan input maka dharus bekerja sebentar pada inputnya setelah membaca semua itu agar pendekatan Anda membuat perbedaan.
Hauke ​​Laging

Jawaban:


6
a | b | { c; [notify];} | d

Pemberitahuan dapat dilakukan misalnya dengan sinyal ke PID yang telah diteruskan dalam variabel lingkungan ( kill -USR1 $EXTPID) atau dengan membuat file ( touch /path/to/file).

Ide lain:

Anda menjalankan proses selanjutnya (yang dapat memulai yang Anda tunggu) dari pipa:

a | b | { c; exec >&-; nextprocess;} | d

atau

a | b | { c; exec >&-; nextprocess &} | d

Terima kasih. Tapi kemudian, membuat file sementara untuk output antara lebih verbose dan lebih mudah diurai (untuk manusia). Juga, bagaimana saya menghindari kondisi balapan dengan sinyal? ... Saya berharap untuk solusi yang lebih bersih, tetapi jika ini adalah cara untuk pergi, maka jadilah itu.
krlmlr

@ krlmlr Kondisi lomba apa?
Hauke ​​Laging

notifydapat dieksekusi sebelum saya memasang perangkap sinyal. Bagaimana saya bisa memastikan untuk tidak melewatkan sinyal itu?
krlmlr

@ krlmlr Anda menghentikan skrip yang memanggil pipeline sampai ia menerima sinyal itu sendiri yang dikirim setelah traptelah ditentukan.
Hauke ​​Laging

Suntingan Anda: Pipa disebut dalam satu lingkaran, di mana saya tidak memiliki kendali. Sayangnya, { c; bg; }atau { c; exit 0; }sepertinya tidak berhasil.
krlmlr

5

Jika saya memahami pertanyaan Anda dengan benar, ini akan berhasil:

a | b | c | { (exec <&3 3<&-; d) &} 3<&0

(Trik fd 3 adalah karena beberapa (kebanyakan) shell mengarahkan stdin ke / dev / null with &).



3

Inilah yang saya temukan dengan coba-coba, dengan bantuan masukan Hauke:

a | b | { c; kill -PIPE $$; } | d

Setara:

a | b | ( c; kill -PIPE $$; ) | d

(Yang terakhir lebih eksplisit, karena {}akan berjalan dalam subkulit pula jika di dalam pipa.)

Beberapa sinyal lain (termasuk QUIT, TERMdan USR1) berfungsi juga, namun dalam hal ini deskripsi sinyal ditampilkan pada terminal.

Saya ingin tahu apakah ini maksud asli dari PIPEsinyal. Menurut manual :

SIGPIPE: PIPESinyal dikirim ke proses ketika mencoba menulis ke pipa tanpa proses yang terhubung ke ujung lainnya.

Ini berarti bahwa ketika saya secara artifisial mengirim sinyal pipa ke subkulit, itu diam-diam berakhir, meninggalkan konsumen akhir ( d) sendirian.

Ini bekerja di kedua shdan bash.


0

Anda dapat menggunakan spongeprogram dari paket "moreutils":

a | b | c | sponge | d

spons akan digunakan untuk akhir ckeluaran sebelum disalurkan ke d. Semoga itu yang Anda inginkan.


0

Anda bisa melakukannya:

a | b | c | (d ; cat > /dev/null)

Jadi, ketika dselesai, catakan menyerap sisa coutput sampai selesai.

Baik. Setelah komentar, saya pikir jawabannya adalah langsung mulai ddi latar belakang.

Melakukan:

a | b | c | (d &)

atau gunakan solusi Stephane Chazelas jika ada masalah dengan dmembaca dari stdin .


Saya khawatir kasus penggunaan saya agak sebaliknya: cselesai lebih awal dari d, dan saya harus menunggu sampai cselesai tetapi tidak peduli d.
krlmlr

Maaf, saya tidak mengerti. Apa yang ingin Anda lakukan ketika cselesai dan dmasih berjalan? Bunuh d?
angus

dmemiliki GUI dan dapat berjalan hingga pengguna menutupnya.
krlmlr

OKE ... tapi ini sudah terjadi. Ketika a,, bdan cmenyelesaikan pekerjaan mereka, mereka menutup stdout dan keluar; dan hanya dtetap berjalan. Apakah Anda ingin mengirim dke latar belakang saat cselesai? Itu saja?
angus

Ya, dharus dikirim ke latar belakang setelah cselesai.
krlmlr
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.