Mengapa bash mengabaikan SIGTERM?

10

Terkadang ketika saya ingin logout dengan cepat saya lakukan kill -15 -1. Saya perhatikan bahwa bash mengabaikan SIGTERM.

Aku bertanya-tanya apa alasan untuk perilaku bash seperti itu ?

Tidak terlalu UNIX untuk mengabaikan SIGTERM tanpa alasan yang bagus, bukan?

MEMPERBARUI:

efek yang sama (tidak) untuk semua:

$ kill -TERM $$
$ type kill
kill is a shell builtin
$ command kill -TERM $$
$ /bin/kill -TERM $$

UPDATE2:

Dari man bash :

Ketika bash bersifat interaktif, tanpa adanya perangkap, ia mengabaikan SIGTERM

Jadi itu dilakukan dengan sengaja. Tapi kenapa?

Michał Šrajer
sumber
Pembunuhan mana yang Anda gunakan? /bin/killatau shell builtin? Jika yang terakhir, saya menduga bahwa shell tidak akan bunuh diri dengan builtin sendiri.
terdon
@terdon: Saya menggunakan builtin, tapi saya tidak berpikir itu alasan untuk tidak membunuhnya sendiri.
Michał Šrajer
1
Jika Anda ingin keluar dengan cepat, gunakan Ctrl + d
YoMismo
1
@YoMismo: "keluar dari sesi X"
Michał Šrajer
2
@ MichałŠrajer: Ctrl-Alt-Backspace melakukan ini untuk saya di Xorg ... Anda mungkin harus mengaktifkannya di xorg.conf, meskipun.
Laszlo Valko

Jawaban:

10

Pertama, ini tidak spesifik untuk bash. ATT ksh, dash, dan zsh berperilaku sama: mereka mengabaikan SIGTERM dan SIGQUIT selama edisi baris perintah; Adapun mksh, itu juga tidak berhenti tetapi memperlakukan mereka seperti SIGINT.

Baik manual ksh dan manual bash membenarkan mengabaikan SIGTERM dalam istilah ini:

sehingga kill 0tidak membunuh shell interaktif

kill 0membunuh semua proses dalam grup proses di mana shell berada¹. Singkatnya, grup proses terdiri dari semua proses yang berjalan di latar depan pada terminal, atau semua proses di latar belakang atau pekerjaan yang ditangguhkan.

Lebih tepatnya, inilah yang terjadi pada cangkang modern dengan kontrol pekerjaan . Dalam shell seperti itu, kill 0tidak akan berguna, karena shell akan berada dalam grup proses sendiri. Kerang yang lebih lama (atau kerang modern setelah set +m) tidak membuat grup proses untuk perintah latar belakang. Jadi Anda dapat menggunakan perintah kill 0untuk mematikan semua perintah latar belakang tanpa keluar. ² Dengan demikian kill 0alasannya terlihat seperti yang lama yang tidak lagi dibenarkan saat ini tetapi disimpan untuk kompatibilitas mundur.

Namun ada situasi serupa lainnya di mana membuat shell kebal berguna. Pertimbangkan kasus di mana Anda memiliki proses memonopoli terminal dan Anda ingin membunuhnya tanpa keluar. Banyak sistem memiliki alat seperti pkillyang memungkinkan Anda membunuh proses yang berjalan pada terminal. Anda dapat menjalankan pkill -t $TTYatau pkill -QUIT -t $TTYmematikan semua proses yang berjalan pada terminal saat ini, kecuali shell yang mengabaikan sinyal.

Sebuah shell biasanya hilang ketika pengguna keluar (dengan perintah seperti exitatau logout), atau ketika terminalnya menandakan akhir input (pengguna dapat menyebabkan ini dengan menekan Ctrl+ D) atau hilang sama sekali. Dalam kasus terakhir ini, shell menerima sinyal SIGHUP, dan shell tidak mengabaikan yang itu.

Untuk kasus penggunaan Anda keluar dari sesi X, kill -15 -1akan melakukannya, karena itu membunuh emulator terminal yang menyebabkan shell menerima SIGHUP. Sebenarnya cukup untuk membunuh server X, tetapi itu membutuhkan menemukan ID prosesnya. Jika Anda ingin perintah yang sama berfungsi pada sesi teks, Anda dapat menggunakannya kill -15 -1; exit. Lagipula itu perintah yang cukup berbahaya untuk dimiliki.

¹ Ini sepertinya tidak disebutkan dalam manual shell sebagai aturan; itu fitur panggilan sistem yang mendasarinya. Itu disebutkan secara eksplisit dalam spesifikasi POSIX .
² Saat ini, untuk melakukan itu, jalankan jobs -luntuk melihat daftar pekerjaan dengan ID grup proses mereka, kemudian kill -123 -456 …untuk membunuh grup proses.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
5

Ini mungkin menjawab pertanyaan Anda:

Ketika Bash bersifat interaktif, jika tidak ada jebakan, ia mengabaikan SIGTERM (sehingga 'kill 0' tidak membunuh shell interaktif), dan SIGINT ditangkap dan ditangani (sehingga wait builtin dapat interruptible). Ketika Bash menerima SIGINT, ia keluar dari setiap loop eksekusi. Dalam semua kasus, Bash mengabaikan SIGQUIT. Jika kontrol pekerjaan berlaku (lihat Kontrol Pekerjaan), Bash mengabaikan SIGTTIN, SIGTTOU, dan SIGTSTP.

Perintah non-builtin yang dimulai oleh Bash memiliki penangan sinyal diatur ke nilai-nilai yang diwarisi oleh shell dari induknya. Ketika kontrol pekerjaan tidak berlaku, perintah asinkron mengabaikan SIGINT dan SIGQUIT sebagai tambahan dari penangan bawaan ini. Perintah dijalankan sebagai akibat dari penggantian perintah mengabaikan sinyal kontrol pekerjaan yang dihasilkan keyboard SIGTTIN, SIGTTOU, dan SIGTSTP.

Shell keluar secara default setelah menerima SIGHUP. Sebelum keluar, shell interaktif mengirim ulang SIGHUP ke semua pekerjaan, berjalan atau berhenti. Pekerjaan yang dihentikan dikirim SIGCONT untuk memastikan bahwa mereka menerima SIGHUP. Untuk mencegah shell mengirimkan sinyal SIGHUP ke pekerjaan tertentu, itu harus dihapus dari tabel pekerjaan dengan builtin disown (lihat Pekerjaan Control Builtins) atau ditandai untuk tidak menerima SIGHUP menggunakan disown -h.

Jika opsi shell huponexit telah diatur dengan shopt (lihat The Shopt Builtin), Bash mengirimkan SIGHUP ke semua pekerjaan ketika shell login interaktif keluar.

Jika Bash sedang menunggu perintah untuk menyelesaikan dan menerima sinyal yang perangkap telah ditetapkan, perangkap tidak akan dieksekusi sampai perintah selesai. Ketika Bash sedang menunggu perintah asinkron melalui wait builtin, penerimaan sinyal di mana trap telah diatur akan menyebabkan wait builtin kembali segera dengan status keluar lebih besar dari 128, segera setelah itu trap dieksekusi.

SUMBER : Manual Bash GNU

Petr
sumber
Saya mengutip ini di pembaruan saya2. Manusia menyatakan bahwa bash sedang melakukannya, tetapi tidak menjelaskan mengapa keputusan seperti itu. Pertanyaannya tetap - mengapa?
Michał Šrajer