Banyak contoh untuk trap
digunakan trap ... INT TERM EXIT
untuk tugas pembersihan. Tetapi apakah benar-benar perlu untuk mendaftar ketiga sigspec?
Manual mengatakan:
Jika SIGNAL_SPEC EXIT (0) ARG dijalankan saat keluar dari shell.
yang saya percaya berlaku apakah skrip selesai secara normal atau selesai karena diterima SIGINT
atau SIGTERM
. Eksperimen juga menegaskan keyakinan saya:
$ cat ./trap-exit
#!/bin/bash
trap 'echo TRAP' EXIT
sleep 3
$ ./trap-exit & sleep 1; kill -INT %1
[1] 759
TRAP
[1]+ Interrupt ./trap-exit
$ ./trap-exit & sleep 1; kill -TERM %1
[1] 773
TRAP
[1]+ Terminated ./trap-exit
Lalu mengapa begitu banyak contoh mendaftar semuanya INT TERM EXIT
? Atau apakah saya melewatkan sesuatu dan apakah ada kasus di mana solonya EXIT
akan terlewatkan?
INT TERM EXIT
kode pembersihan dijalankan dua kali ketikaSIGTERM
atauSIGINT
diterima.Jawaban:
The POSIX spesifikasi tidak mengatakan banyak tentang kondisi dihasilkan dalam melaksanakan perangkap EXIT, hanya tentang apa lingkungannya harus terlihat seperti ketika dieksekusi.
Dalam shell ash Busybox, tes keluar perangkap Anda tidak menggemakan 'TRAP' sebelum keluar karena SIGINT atau SIGTERM. Saya menduga ada beberapa kerang lain yang mungkin tidak berfungsi dengan baik.
sumber
dash
juga tidak menjebak hanyaEXIT
ketika diterimaSIGINT/SIGTERM
.zsh
juga - dengan demikian, mungkinbash
adalah satu-satunya shell di manaEXIT
juga cocok dengan sinyal.zsh
tidak menjebakEXIT
ketika itu diterimaINT
, tetapi itu ketika menerimaTERM
. EDIT: Saya baru tahu berapa umur ini ...Ya, ada perbedaan.
Skrip ini akan keluar saat Anda menekan Enter, atau mengirimnya
SIGINT
atauSIGTERM
:Script ini akan keluar ketika Anda menekan Enter:
* Diuji dalam sh , Bash , dan Zsh . (tidak lagi berfungsi di sh saat Anda menambahkan perintah agar trap dijalankan)
Ada juga yang dikatakan @Shawn: Ash dan Dash tidak menangkap sinyal
EXIT
.Jadi, untuk menangani sinyal dengan kuat, yang terbaik adalah menghindari perangkap
EXIT
sama sekali, dan gunakan sesuatu seperti ini:sumber
mktemp
panggilan.exit
perlucleanup
?ERR
untuk mengatasinya, tetapi tidak portabel .trap - INT TERM; kill -2 $$
sebagai baris terakhir dari pembersihan, untuk memberi tahu induk shell bahwa ia keluar sebelum waktunya. Jika shell induk foobar.sh memanggil skrip Anda (foo.sh), dan kemudian memanggil bar.sh, Anda tidak ingin bar.sh dijalankan jika INT / TERM dikirimkan ke foo.sh.trap cleanup EXIT
akan menangani propagasi ini secara otomatis, jadi IMO yang paling kuat. Ini juga berarti Anda tidak perlu meneleponcleanup
di akhir skrip.Menyempurnakan jawaban terakhir, karena memiliki masalah:
Poin di atas:
Penangan INT dan TERM tidak berhenti untuk saya ketika saya menguji - mereka menangani kesalahan kemudian shell kembali ke keluar (dan ini tidak terlalu mengejutkan). Jadi saya memastikan bahwa pembersihan keluar setelah itu, dan dalam kasus sinyal selalu menggunakan kode kesalahan (dan dalam kasus keluar normal, mempertahankan kode kesalahan).
Dengan bash, sepertinya keluar di INT handler juga memanggil EXIT handler, maka saya membuka bukaan keluar handler dan menyebutnya sendiri (yang akan bekerja di shell apa pun tanpa peduli perilaku).
Saya perangkap keluar karena skrip shell dapat keluar sebelum mereka mencapai bagian bawah - kesalahan sintaks, set -e dan bukan nol kembali, cukup memanggil keluar. Anda tidak bisa mengandalkan shellscript untuk sampai ke bawah.
SIGQUIT adalah Ctrl- \ jika Anda belum pernah mencobanya. Memberi Anda bonus coredump. Jadi saya pikir ini juga layak untuk diperangkap, meskipun sedikit tidak jelas.
Pengalaman masa lalu mengatakan jika Anda (seperti saya) selalu menekan Ctrl-C beberapa kali, Anda kadang-kadang akan menangkapnya setengah jalan melalui bagian pembersihan skrip shell Anda, jadi ini berfungsi tetapi tidak selalu sesempurna yang Anda inginkan.
sumber
trap
pemanggil akan mendapatkan 130 untuk SIGINT, 143 untuk SIGTERM, dll Jadi saya akan menangkap dan lulus kode keluar yang benar sebagai:sig_cleanup() { err=$?; trap '' EXIT; (exit $err); cleanup; }
.trap '' EXIT INT TERM
fungsi pembersihan? Apakah ini untuk mencegah gangguan pengguna pembersihan yang Anda sebutkan di paragraf terakhir? Bukankah ituEXIT
berlebihan?