(Terinspirasi oleh jawaban Gilles)
Dengan ISIGset flag, satu-satunya cara agar Childskrip bisa mendapatkan SIGINTtanpa induknya SIGINTadalah dengan skrip itu berada dalam grup prosesnya sendiri. Ini dapat dilakukan dengan set -mopsi.
Jika Anda mengaktifkan -mopsi di Childskrip shell, itu akan melakukan kontrol pekerjaan tanpa menjadi interaktif. Ini akan menyebabkannya menjalankan hal-hal dalam kelompok proses yang terpisah, mencegah orang tua menerima SIGINTketika INTRkarakter dibaca.
Berikut adalah deskripsi -mopsi POSIX :
-mOpsi 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 -mpilihan adalah mirip dengan -i, tetapi tidak mengubah perilaku shell hampir sebanyak -idilakukannya.
Contoh:
yang Parentnaskah:
#!/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 Childnaskah:
#!/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 Childsedang 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 SIGINTpenangan orang tua tidak pernah dieksekusi.
Atau, jika Anda lebih suka memodifikasi Parentbukan Child, Anda dapat melakukan ini:
yang Parentnaskah:
#!/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 Childnaskah (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
SIGINTselama Child. Ini tidak menjawab pertanyaan Anda, tetapi mungkin memberi Anda apa yang Anda inginkan.
- Ubah
Childke:
- Gunakan
stty -guntuk membuat cadangan pengaturan terminal saat ini.
- Jalankan
stty -isigtidak menghasilkan sinyal dengan INTR, QUIT, dan SUSPkarakter.
- Di latar belakang, baca input terminal dan kirim sendiri sinyal yang sesuai (mis. Jalankan
kill -QUIT 0ketika Control+ \dibaca, kill -INT $$ketika Control+ Cdibaca). Ini bukan hal sepele, dan mungkin tidak mungkin untuk membuatnya bekerja dengan lancar jika Childskrip 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 setpgidutilitas 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,SIGQUITdanSIGTERMdiabaikan.