Saya ingin skrip shell saya gagal setiap kali perintah dieksekusi dengan mereka gagal.
Biasanya saya melakukannya dengan:
set -e
set -o pipefail
(biasanya saya tambahkan set -u
juga)
Masalahnya adalah bahwa tidak ada yang di atas bekerja dengan substitusi proses. Kode ini mencetak "ok" dan keluar dengan kode pengembalian = 0, sementara saya ingin gagal:
#!/bin/bash -e
set -o pipefail
cat <(false) <(echo ok)
Apakah ada yang setara dengan "pipefail" tetapi untuk substitusi proses? Adakah cara lain untuk meneruskan ke perintah output dari perintah seperti itu adalah file, tetapi meningkatkan kesalahan setiap kali salah satu program gagal?
Solusi orang miskin akan mendeteksi jika perintah-perintah itu menulis ke stderr (tetapi beberapa perintah menulis ke stderr dalam skenario sukses).
Solusi lain yang lebih sesuai dengan posix adalah menggunakan pipa bernama, tapi saya perlu menjalankan perintah-perintah-yang-menggunakan-proses sebagai oneliners yang dibangun dengan cepat dari kode yang dikompilasi, dan membuat pipa bernama akan mempersulit hal-hal (perintah tambahan, menjebak kesalahan untuk menghapusnya, dll.)
sumber
mkfifo pipe; { rm pipe; cat <file; } >pipe
. Perintah itu akan digantung sampai pembaca membukapipe
karena itu adalah shell yang melakukanopen()
dan begitu begitu ada pembaca padapipe
tautan fs untukpipe
isrm
'd dan kemudiancat
salinan infile keluar ke deskriptor shell untuk pipa itu.: <( ! : || kill -2 "$$")
$$
substitusi tidak berfungsi untuk saya, karena substitusi perintah tidak dilakukan karena perintah yang menggunakan proses substitusi dilakukan di dalam pipeline perintah yang dihasilkan dari kode "non shell" (python). Mungkin saya harus membuat subproses dengan python dan mengirimkannya secara terprogram.kill -2 0
.Jawaban:
Anda hanya bisa mengatasi masalah itu dengan itu misalnya:
Subshell dari skrip adalah
SIGTERM
d sebelum perintah kedua dapat dieksekusi (other_command
). Theecho ok
perintah dijalankan "kadang-kadang": Masalahnya adalah bahwa proses substitusi asynchronous. Tidak ada jaminan bahwakill $$
perintah dijalankan sebelum atau setelah ituecho ok
perintah. Ini masalah penjadwalan sistem operasi.Pertimbangkan skrip bash seperti ini:
Output dari skrip itu bisa:
Atau:
Anda dapat mencobanya dan setelah beberapa kali mencoba, Anda akan melihat dua pesanan yang berbeda di output. Dalam yang pertama skrip dihentikan sebelum dua
echo
perintah lainnya bisa menulis ke deskriptor file. Dalam yang kedua perintahfalse
ataukill
mungkin dijadwalkan setelahecho
perintah.Atau untuk lebih tepatnya: Sistem panggilan
signal()
darikill
utillity yang mengirim paraSIGTERM
sinyal ke proses kerang dijadwalkan (atau disampaikan) atau lebih lambat dari gemawrite()
syscalls.Namun, skrip berhenti dan kode keluar bukan 0. Karenanya harus menyelesaikan masalah Anda.
Solusi lain , tentu saja, menggunakan pipa bernama untuk ini. Tapi, itu tergantung pada skrip Anda seberapa kompleks untuk mengimplementasikan pipa bernama atau solusi di atas.
Referensi:
sumber
Sebagai catatan, dan bahkan jika jawaban dan komentarnya bagus dan bermanfaat, saya akhirnya menerapkan sesuatu yang sedikit berbeda (saya memiliki beberapa batasan tentang menerima sinyal dalam proses induk yang tidak saya sebutkan dalam pertanyaan)
Pada dasarnya, saya akhirnya melakukan sesuatu seperti ini:
Lalu saya periksa file kesalahan. Jika ada, saya tahu sub-perintah apa yang gagal (dan isi dari error_file dapat bermanfaat). Lebih bertele-tele dan meretas yang awalnya saya inginkan, tetapi kurang rumit daripada membuat pipa bernama dalam perintah bash satu-liner.
sumber
Contoh ini menunjukkan cara menggunakan
kill
bersamatrap
.Tetapi
kill
tidak dapat meneruskan kode kembali dari sub proses Anda ke proses induk.sumber
Dengan cara yang sama seperti Anda akan mengimplementasikan
$PIPESTATUS
/$pipestatus
dengan shell POSIX yang tidak mendukungnya , Anda dapat memperoleh status keluar dari perintah dengan mengirimkannya melalui pipa:Pemberian yang mana:
Atau Anda bisa menggunakan
pipefail
dan mengimplementasikan proses substitusi dengan tangan seperti yang Anda lakukan dengan shell yang tidak mendukungnya:sumber