Jika saya menggunakan trap
seperti dijelaskan misalnya pada http://linuxcommand.org/wss0160.php#trap untuk menangkap ctrl-c (atau serupa) dan pembersihan sebelum keluar maka saya mengubah kode keluar kembali.
Sekarang ini mungkin tidak akan membuat perbedaan di dunia nyata (misalnya karena kode keluar tidak portabel dan di atas itu tidak selalu jelas seperti yang dibahas dalam kode keluar default ketika proses dihentikan? ) Tapi masih saya bertanya-tanya apakah ada benar-benar tidak ada cara untuk mencegah itu dan mengembalikan kode kesalahan default untuk skrip yang terputus?
Contoh (dalam bash, tapi pertanyaan saya tidak boleh dianggap spesifik-bash):
#!/bin/bash
trap 'echo EXIT;' EXIT
read -p 'If you ctrl-c me now my return code will be the default for SIGTERM. ' _
trap 'echo SIGINT; exit 1;' INT
read -p 'If you ctrl-c me now my return code will be 1. ' _
Keluaran:
$ ./test.sh # doing ctrl-c for 1st read
If you ctrl-c me now my return code will be the default for SIGTERM.
$ echo $?
130
$ ./test.sh # doing ctrl-c for 2nd read
If you ctrl-c me now my return code will be the default for SIGTERM.
If you ctrl-c me now my return code will be 1. SIGINT
EXIT
$ echo $?
1
(Diedit untuk menghapus agar lebih sesuai dengan POSIX.)
(Diedit lagi untuk menjadikannya skrip bash sebagai gantinya, pertanyaan saya tidak spesifik untuk shell.)
Diedit untuk menggunakan "INT" portabel untuk jebakan yang mendukung "SIGINT" non-portabel.
Diedit untuk menghilangkan kawat gigi keriting yang tidak berguna dan menambahkan solusi potensial.
Memperbarui:
Saya memecahkannya sekarang dengan hanya keluar dengan beberapa kode kesalahan hardcoded dan menjebak EXIT. Ini mungkin bermasalah pada sistem tertentu karena kode kesalahan mungkin berbeda atau perangkap EXIT tidak mungkin tetapi dalam kasus saya cukup OK.
trap cleanup EXIT
trap 'exit 129' HUP
trap 'exit 130' INT
trap 'exit 143' TERM
read
untuk membaca dari proses yang sekarang dantrap cmd SIGINT
tidak akan berfungsi seperti yang dikatakan standar yang harus Anda gunakantrap cmd INT
.read -p
membaca input dari proses saat ini.Jawaban:
Yang perlu Anda lakukan adalah mengubah handler EXIT di dalam handler pembersihan Anda. Ini sebuah contoh:
sumber
trap cleanup INT
bukantrap cleanup EXIT
?Sebenarnya, menginterupsi internal bash
read
tampaknya sedikit berbeda dengan menginterupsi perintah yang dijalankan oleh bash. Biasanya, ketika Anda masuktrap
,$?
diatur dan Anda dapat mempertahankannya dan keluar dengan nilai yang sama:Jika skrip Anda terputus saat menjalankan perintah suka
sleep
atau bahkan sejenis bawaanwait
, Anda akan melihatdan kode keluar adalah 130. Namun, untuk
read -p
, tampaknya$?
adalah 0 (pada versi saya dari bash 4.3.42).Penanganan sinyal selama
read
mungkin sedang berlangsung, sesuai dengan file perubahan dalam rilis saya ... (/ usr / share / doc / bash / CHANGES)sumber
read
, seperti dicatat dalam file PERUBAHAN (ditambahkan ke jawaban saya). Jadi, itu mungkin sedang dalam proses.128 + signo
sebagai kode keluar untuk sinyal, ksh93 menggunakan256 + signo
. POSIX mengatakan: sesuatu di atas 128 ....Kode keluar sinyal yang biasa akan tersedia pada
$?
saat masuk ke penangan perangkap:Jika ada jebakan EXIT yang terpisah, Anda dapat menggunakan metodologi yang sama: segera pertahankan status keluar dari penangan sinyal (jika ada) bersih-bersih, lalu kembalikan status keluar yang disimpan.
sumber
local
bukan POSIX.{ba,z}sh
. AFAIK, itu yang terbaik yang bisa dilakukan, terlepas dari itu.$?
adalah 1 apa pun sinyal yang diterima).Hanya mengembalikan beberapa kode kesalahan tidak cukup untuk mensimulasikan keluar oleh SIGINT. Saya terkejut bahwa tidak ada yang menyebutkan sejauh ini. Bacaan lebih lanjut: https://www.cons.org/cracauer/sigint.html
Cara yang tepat adalah:
Ini bekerja dengan Bash, Dash, dan zsh. Untuk portabilitas lebih lanjut, Anda perlu menggunakan spesifikasi sinyal numerik (di sisi lain, zsh mengharapkan parameter string untuk
kill
perintah ...)Perhatikan juga perlakuan khusus dari
EXIT
sinyal. Hal ini disebabkan oleh beberapa cangkang (yaitu Bash) yang menjalankan jebakanEXIT
untuk setiap sinyal juga (setelah jebakan yang mungkin ditentukan pada sinyal itu). ResetEXIT
perangkap mencegah hal itu.Hanya mengeksekusi kode saat keluar "normal"
Pemeriksaan
[ $sig = EXIT ]
memungkinkan untuk mengeksekusi kode hanya pada jalan keluar yang normal (non-sinyal). Namun, semua sinyal harus memiliki jebakan yang pada akhirnya mengatur ulang jebakan padaEXIT
saat itu;normal_exit_only_cleanup
juga akan dipanggil untuk sinyal yang tidak. Ini juga akan dieksekusi melalui pintu keluarset -e
. Ini dapat diperbaiki dengan menjebakERR
(yang tidak didukung oleh Dash) dan menambahkan tanda centang[ $sig = ERR ]
sebelumkill
.Versi Bash-only yang disederhanakan
Di sisi lain, perilaku ini berarti bahwa di Bash Anda bisa melakukannya
untuk hanya menjalankan beberapa kode pembersihan dan mempertahankan status keluar.
diedit
Perilaku rumit Bash tentang "EXIT menjebak semuanya"
Hapus sinyal KILL, yang tidak bisa dijebak
Hapus awalan SIG dari nama sinyal
Jangan berusaha
kill -s EXIT
Ambil
set -e
/ ERR memperhitungkansumber
SIGINT
adalah cara untuk mematikannya dan mungkin memutuskan untuk keluar dengan 0 jika ia berhasil berakhir tanpa kesalahan atau kode kesalahan lain jika tidak dimatikan dengan benar. Contoh kasus:top
. Jalankantop; echo $?
lalu tekan Ctrl-C. Status yang dibuang di layar adalah 0.