(Terinspirasi oleh jawaban Gilles)
Dengan ISIG
set flag, satu-satunya cara agar Child
skrip bisa mendapatkan SIGINT
tanpa induknya SIGINT
adalah dengan skrip itu berada dalam grup prosesnya sendiri. Ini dapat dilakukan dengan set -m
opsi.
Jika Anda mengaktifkan -m
opsi di Child
skrip shell, itu akan melakukan kontrol pekerjaan tanpa menjadi interaktif. Ini akan menyebabkannya menjalankan hal-hal dalam kelompok proses yang terpisah, mencegah orang tua menerima SIGINT
ketika INTR
karakter dibaca.
Berikut adalah deskripsi -m
opsi POSIX :
-m
Opsi ini harus didukung jika implementasi mendukung opsi Utilitas Portabilitas Pengguna. Semua pekerjaan harus dijalankan dalam kelompok proses mereka sendiri. Segera sebelum shell mengeluarkan prompt setelah penyelesaian pekerjaan latar belakang, sebuah pesan yang melaporkan status keluar dari pekerjaan latar belakang harus ditulis ke kesalahan standar. Jika pekerjaan latar depan berhenti, shell harus menulis pesan ke kesalahan standar untuk efek itu, diformat seperti yang dijelaskan oleh utilitas pekerjaan. Selain itu, jika pekerjaan berubah status selain keluar (misalnya, jika berhenti untuk input atau output atau dihentikan oleh sinyal SIGSTOP), shell harus menulis pesan yang sama segera sebelum menulis prompt berikutnya. Opsi ini diaktifkan secara default untuk shell interaktif.
The -m
pilihan adalah mirip dengan -i
, tetapi tidak mengubah perilaku shell hampir sebanyak -i
dilakukannya.
Contoh:
yang Parent
naskah:
#!/bin/sh
trap 'echo "PARENT: caught SIGINT; exiting"; exit 1' INT
echo "PARENT: pid=$$"
echo "PARENT: Spawning child..."
./Child
echo "PARENT: child returned"
echo "PARENT: exiting normally"
yang Child
naskah:
#!/bin/sh -m
# ^^
# notice the -m option above!
trap 'echo "CHILD: caught SIGINT; exiting"; exit 1' INT
echo "CHILD: pid=$$"
echo "CHILD: hit enter to exit"
read foo
echo "CHILD: exiting normally"
Inilah yang terjadi ketika Anda menekan Control+ Cketika Child
sedang menunggu input:
$ ./Parent
PARENT: pid=12233
PARENT: Spawning child...
CHILD: pid=12234
CHILD: hit enter to exit
^CCHILD: caught SIGINT; exiting
PARENT: child returned
PARENT: exiting normally
Perhatikan bagaimana SIGINT
penangan orang tua tidak pernah dieksekusi.
Atau, jika Anda lebih suka memodifikasi Parent
bukan Child
, Anda dapat melakukan ini:
yang Parent
naskah:
#!/bin/sh
trap 'echo "PARENT: caught SIGINT; exiting"; exit 1' INT
echo "PARENT: pid=$$"
echo "PARENT: Spawning child..."
sh -m ./Child # or 'sh -m -c ./Child' if Child isn't a shell script
echo "PARENT: child returned"
echo "PARENT: exiting normally"
yang Child
naskah (normal, tidak perlu untuk -m
):
#!/bin/sh
trap 'echo "CHILD: caught SIGINT; exiting"; exit 1' INT
echo "CHILD: pid=$$"
echo "CHILD: hit enter to exit"
read foo
echo "CHILD: exiting normally"
Ide alternatif
- Ubah proses lain dalam grup proses latar depan untuk mengabaikan
SIGINT
selama Child
. Ini tidak menjawab pertanyaan Anda, tetapi mungkin memberi Anda apa yang Anda inginkan.
- Ubah
Child
ke:
- Gunakan
stty -g
untuk membuat cadangan pengaturan terminal saat ini.
- Jalankan
stty -isig
tidak menghasilkan sinyal dengan INTR
, QUIT
, dan SUSP
karakter.
- Di latar belakang, baca input terminal dan kirim sendiri sinyal yang sesuai (mis. Jalankan
kill -QUIT 0
ketika Control+ \dibaca, kill -INT $$
ketika Control+ Cdibaca). Ini bukan hal sepele, dan mungkin tidak mungkin untuk membuatnya bekerja dengan lancar jika Child
skrip atau apa pun yang dijalankan dimaksudkan untuk bersifat interaktif.
- Kembalikan pengaturan terminal sebelum keluar (idealnya dari jebakan aktif
EXIT
).
- Sama seperti # 2 kecuali daripada menjalankan
stty -isig
, tunggu pengguna untuk menekan Enteratau kunci non-khusus lainnya sebelum membunuh Child
.
Tulis setpgid
utilitas Anda sendiri dalam C, Python, Perl, dll. Yang dapat Anda gunakan untuk menelepon setpgid()
. Berikut ini adalah implementasi C mentah:
#define _XOPEN_SOURCE 700
#include <unistd.h>
#include <signal.h>
int
main(int argc, char *argv[])
{
// todo: add error checking
void (*backup)(int);
setpgid(0, 0);
backup = signal(SIGTTOU, SIG_IGN);
tcsetpgrp(0, getpid());
signal(SIGTTOU, backup);
execvp(argv[1], argv + 1);
return 1;
}
Contoh penggunaan dari Child
:
#!/bin/sh
[ "${DID_SETPGID}" = true ] || {
# restart self after calling setpgid(0, 0)
exec env DID_SETPGID=true setpgid "$0" "$@"
# exec failed if control reached this point
exit 1
}
unset DID_SETPGID
# do stuff here
ksh
). Contoh:${ENV}
bersumber, shell tidak akan segera keluar ketika menemukan kesalahan,SIGQUIT
danSIGTERM
diabaikan.