Apa yang terjadi adalah bahwa baik bash
dan ping
menerima SIGINT ( bash
menjadi tidak interaktif, baik ping
dan bash
berjalan dalam kelompok proses yang sama yang telah dibuat dan ditetapkan sebagai kelompok proses latar depan terminal oleh shell interaktif Anda berlari bahwa script dari).
Namun, bash
menangani SIGINT itu secara tidak sinkron, hanya setelah perintah yang saat ini berjalan telah keluar. bash
hanya keluar setelah menerima SIGINT itu jika perintah yang sedang berjalan mati karena SIGINT (yaitu status keluarnya menunjukkan bahwa ia telah dibunuh oleh SIGINT).
$ bash -c 'sh -c "trap exit\ 0 INT; sleep 10; :"; echo here'
^Chere
Di atas, bash
, sh
dan sleep
menerima SIGINT ketika saya menekan Ctrl-C, tapi sh
keluar biasanya dengan kode 0 keluar, sehingga bash
mengabaikan SIGINT, yang sebabnya kita melihat "di sini".
ping
, setidaknya yang dari iputils, berperilaku seperti itu. Ketika terganggu, ia mencetak statistik dan keluar dengan status keluar 0 atau 1 tergantung pada apakah pingnya dijawab atau tidak. Jadi, ketika Anda menekan Ctrl-C saat ping
sedang berjalan, bash
perhatikan bahwa Anda telah menekan Ctrl-C
di penangan SIGINT-nya, tetapi karena ping
keluar secara normal, bash
tidak keluar.
Jika Anda menambahkan sleep 1
dalam loop itu dan tekan Ctrl-C
saat sleep
sedang berjalan, karena sleep
tidak memiliki penangan khusus pada SIGINT, itu akan mati dan melaporkan bash
bahwa itu mati karena SIGINT, dan dalam kasus itubash
akan keluar (itu benar-benar akan bunuh diri dengan SIGINT sehingga untuk melaporkan gangguan ke induknya).
Mengenai mengapa bash
berperilaku seperti itu, saya tidak yakin dan saya perhatikan perilaku tidak selalu deterministik. Saya baru saja mengajukan pertanyaan pada bash
milis pengembangan ( Pembaruan : @Jilles sekarang telah menemukan alasannya dalam jawabannya ).
Satu-satunya shell lain yang saya temukan berperilaku serupa adalah ksh93 (Pembaruan, seperti yang disebutkan oleh @Jilles, begitu juga FreeBSDsh
). Di sana, SIGINT tampaknya benar-benar diabaikan. Dan ksh93
keluar setiap kali perintah dibunuh oleh SIGINT.
Anda mendapatkan perilaku yang sama seperti di bash
atas tetapi juga:
ksh -c 'sh -c "kill -INT \$\$"; echo test'
Tidak menampilkan "tes". Yaitu, ia keluar (dengan membunuh dirinya sendiri dengan SIGINT di sana) jika perintah yang ditungguinya mati oleh SIGINT, bahkan jika itu, ia sendiri tidak menerima SIGINT itu.
Pekerjaan di sekitar adalah menambahkan:
trap 'exit 130' INT
Di bagian atas skrip untuk memaksa bash
keluar setelah menerima SIGINT (perhatikan bahwa dalam hal apa pun, SIGINT tidak akan diproses secara serempak, hanya setelah perintah yang saat ini berjalan telah keluar).
Idealnya, kami ingin melaporkan kepada orang tua kami bahwa kami meninggal karena SIGINT (sehingga jika itu adalah bash
skrip lain misalnya, bash
skrip itu juga terputus). Melakukan exit 130
tidak sama dengan sekarat SIGINT (meskipun beberapa shell akan diatur$?
nilai yang sama untuk kedua kasus), namun sering digunakan untuk melaporkan kematian oleh SIGINT (pada sistem di mana SIGINT adalah 2 yang paling banyak).
Namun untuk bash
, ksh93
atau FreeBSD sh
, itu tidak berhasil. 130 status keluar tidak dianggap sebagai kematian oleh SIGINT dan skrip induk tidak akan dibatalkan di sana.
Jadi, alternatif yang mungkin lebih baik adalah bunuh diri dengan SIGINT setelah menerima SIGINT:
trap '
trap - INT # restore default INT handler
kill -s INT "$$"
' INT
for f in *.txt; do vi "$f"; cp "$f" newdir; done
. Jika pengguna mengetik Ctrl + C saat mengedit salah satu file,vi
cukup tampilkan pesan. Tampaknya masuk akal bahwa perulangan harus dilanjutkan setelah pengguna selesai mengedit file. (Dan ya, saya tahu Anda bisa mengatakanvi *.txt; cp *.txt newdir
; Saya hanya mengirimkanfor
perulangan sebagai contoh.)