Bisakah program selanjutnya dalam saluran pipa melihat kode keluar dari program sebelumnya?

8

Saya ingin membuat pipeline skrip Bash seperti ini

prog1 | prog2

sedemikian rupa sehingga prog2 dapat melihat kode keluar dari prog1 dan bertindak secara berbeda berdasarkan informasi itu.

Apakah ini mungkin?

dan
sumber
Bisakah Anda menguraikan tindakan secara berbeda bagian dari pertanyaan Anda?
devnull
Anda memiliki kontrol terbatas atas seberapa jauh prog2kemajuan terjadi ketika prog1keluar, karena buffering internal yang digunakan untuk mengimplementasikan pipa dan bagaimana prog1dan prog2dijadwalkan.
chepner
Lihat juga [Dalam urutan apa perintah pipa dijalankan?] (Unix.stackexchange.com/q/37508)
DK Bose

Jawaban:

4

Jawaban umum adalah tidak. Dimungkinkan untuk prog2keluar prog1bahkan sebelum mulai (jelas itu tidak dapat terjadi jika prog2benar-benar membaca beberapa input, yang Anda harapkan akan dilakukan jika Anda menggunakannya dalam pipa). Sangat mungkin untuk prog2keluar sebelum prog1; ini terjadi misalnya ketika prog2program pencarian yang keluar segera setelah menemukan kecocokan, dalam hal ini prog1mungkin belum selesai menghasilkan semua data.

Tidak ada cara langsung untuk prog2mengambil status keluar prog1atau bahkan untuk mengetahui yang prog1telah keluar. Yang prog2bisa diketahui hanyalah bahwa prog1ujung pipa itu sudah ditutup, yang bisa dilakukan tanpa sekarat.

Jika Anda ingin mendapatkan status keluar prog1dari prog2, ada dua metode umum: Anda dapat menulisnya ke file, atau Anda dapat mengirimkannya melalui pipa. Mengirim status output sebagai baris terakhir dari data yang disalurkan adalah suatu kemungkinan. Anda harus memastikan untuk tidak memproses baris terakhir sampai Anda tahu bahwa itu adalah baris terakhir, yaitu sampai Anda mencoba membaca baris berikutnya.

{ prog1; echo $?; } | 

Berikut adalah contoh di mana sisi kanan adalah filter teks yang mewarnai setiap baris yang mengandung kata "error" merah. Jika sisi kiri gagal, sisi kanan keluar dengan status yang sama.

{ prog1; echo $?; } | awk '
    NR != 1 {
        if (line ~ /[Ee][Rr][Rr][Oo][Rr]/) print "\033[31m" line "\033[0m";
        else print line;
    }
    {line = $0}
    END {exit($0)}
'
Gilles 'SANGAT berhenti menjadi jahat'
sumber
Saya mencoba { command; echo ${PIPESTATUS[@]}; } | sort | ...agar status keluar lebih dulu di arus. Semuanya sangat menarik!
@ illuminÉ Itu hanya akan berfungsi jika ${PIPESTATUS[@]}diurutkan sebelum apa pun di output dari command. Jika commandmencetak sekelompok angka, atau jika dapat mencetak teks sewenang-wenang, Anda dalam kesulitan: Anda tidak akan dapat membedakan outputnya dari baris status.
Gilles 'SANGAT berhenti menjadi jahat'
Terima kasih, memang hanya berhasil menyortir status sukses ke atas jika perintah tidak mengandung 0 pada outputnya lol. Tgif / dtk.
2

Meskipun Anda bisa dalam beberapa kasus khusus (lihat jawaban lain) Anda tidak bisa dalam setiap kasus. Beberapa program filter hanya akan terus berjalan, sementara yang lain akan menahan semua output, lepaskan dalam satu ledakan, dan kemudian keluar.

Sebagai contoh program "terus berjalan", grepakan server, seperti yang akan tail -f /var/log/some_log_file. Penggunaan sortdalam pipa menyebabkan "kios", karena sortakan mengumpulkan input sampai pipa di depannya menutup. Menggunakan xargsmenambah kerumitan lebih lanjut: apakah program dimulai oleh xargs(mungkin memulai banyak contoh) bagian dari pipa atau tidak?

Bruce Ediger
sumber
-1 karena Anda di mana dipilih untuk merasionalisasi jawaban yang salah.
ctrl-alt-delor
@ Richard Huh? Jawaban Bruce benar (meskipun paragraf kedua sedikit membingungkan).
Gilles 'SANGAT berhenti menjadi jahat'
1

Jawabannya: Tidak secara langsung.

@terdon telah menggambarkan bahwa kode keluar dari perintah sebelumnya di dalam pipa harus dikirim sebagai parameter eksplisit ke perintah berikutnya.

Ingat bahwa pipa hanyalah pemetaan dari STDOUT perintah sebelumnya ke STDIN perintah berikutnya; kode keluar tidak dikeluarkan ke STDOUT (atau STDERR).

pepoluan
sumber
1
-1 karena Anda di mana dipilih untuk mengutip jawaban yang salah, dan tidak banyak bicara.
ctrl-alt-delor
@ Richard cukup adil ... Seharusnya aku memeriksa ulang ... itulah yang terjadi jika aku memaksakan diriku untuk menjawab pertanyaan ketika sangat lelah ...
pepoluan
1

Semua proses, dalam pipa, dimulai sebelum keluar. Oleh karena itu prog2bisa mendapatkan info ini setelah dimulai, itu juga harus menunda pemrosesan sampai prog1keluar, ini bisa menunda pipa. Tampaknya ada masalah mendasar dalam melakukan apa yang Anda minta, bukan batasan OS.

Anda mungkin perlu mempertimbangkan file sementara, atau meletakkan hasilnya dalam variabel.

Contoh untuk sejumlah kecil data, menggunakan variabel.

tmp=$(prog1)
if test "z$PIPESTATUS" == "z0"
then
   
else
   
fi
ctrl-alt-delor
sumber
Ada celah dalam alasan Anda. prog2dimulai sebelum prog1selesai secara umum, tetapi mungkin ada cara untuk menerima status output dari prog1saat sedang berjalan.
Gilles 'SO- stop being evil'
0

Untuk menyelesaikan jawaban Gilles ,

(prog1; echo $? > /tmp/prog1.status) | prog2

adalah sebuah pendekatan.  prog2bisa juga

  • baca input standar sampai akhir, lalu baca /tmp/prog1.status, atau
  • periksa keberadaan /tmp/prog1.statussecara berkala sambil membaca input standar.
Scott
sumber