(Ispirato dalla risposta di Gilles)
Con il ISIG
flag impostato, l'unico modo per Child
ottenere lo script SIGINT
senza il suo genitore SIGINT
è che sia nel suo gruppo di processi. Questo può essere realizzato con l' set -m
opzione.
Se si attiva l' -m
opzione nello Child
script della shell, eseguirà il controllo del lavoro senza essere interattivo. Ciò causerà l'esecuzione di elementi in un gruppo di processi separato, impedendo al genitore di ricevere il messaggio SIGINT
quando il INTR
personaggio viene letto.
Ecco la descrizione POSIX -m
dell'opzione :
-m
Questa opzione è supportata se l'implementazione supporta l'opzione Utilità di portabilità dell'utente. Tutti i lavori devono essere eseguiti nei rispettivi gruppi di processi. Immediatamente prima che la shell emetta un prompt dopo il completamento del processo in background, un messaggio che riporta lo stato di uscita del processo in background deve essere scritto nell'errore standard. Se un lavoro in primo piano si interrompe, la shell deve scrivere un messaggio di errore standard in tal senso, formattato come descritto dall'utilità lavori. Inoltre, se un lavoro cambia stato diverso dall'uscita (ad esempio, se si arresta per input o output o viene interrotto da un segnale SIGSTOP), la shell deve scrivere un messaggio simile immediatamente prima di scrivere il prompt successivo. Questa opzione è abilitata per impostazione predefinita per le shell interattive.
L' -m
opzione è simile a -i
, ma non altera il comportamento della shell quasi quanto -i
fa.
Esempio:
la Parent
sceneggiatura:
#!/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"
la Child
sceneggiatura:
#!/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"
Questo è ciò che accade quando si preme Control+ Cmentre Child
è in attesa di 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
Nota come il SIGINT
gestore del genitore non viene mai eseguito.
In alternativa, se preferisci modificare Parent
invece di Child
, puoi farlo:
la Parent
sceneggiatura:
#!/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"
lo Child
script (normale; non è necessario -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"
Idee alternative
- Modificare gli altri processi nel gruppo di processi in primo piano da ignorare
SIGINT
per la durata di Child
. Questo non risponde alla tua domanda, ma può darti quello che vuoi.
- Modifica
Child
per:
- Utilizzare
stty -g
per eseguire il backup delle impostazioni correnti del terminale.
- Eseguire
stty -isig
per non generare segnali con i INTR
, QUIT
e SUSP
caratteri.
- Nei precedenti, leggere l'input terminale e inviare i segnali stessi come appropriato (ad esempio, eseguire
kill -QUIT 0
quando Control+ \viene letto, kill -INT $$
quando Control+ Cviene letto). Questo non è banale e potrebbe non essere possibile farlo funzionare senza problemi se lo Child
script o qualsiasi altra cosa venga eseguita è pensata per essere interattiva.
- Ripristina le impostazioni del terminale prima di uscire (idealmente da una trappola attivata
EXIT
).
- Come il n. 2 tranne che in esecuzione
stty -isig
, attendere che l'utente prema Entero qualche altra chiave non speciale prima di uccidere Child
.
Scrivi la tua setpgid
utility in C, Python, Perl, ecc. Che puoi usare per chiamare setpgid()
. Ecco un'implementazione di C grezza:
#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;
}
Esempio di utilizzo da 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
). Esempi:${ENV}
è di provenienza, la shell non si chiude immediatamente quando rileva un erroreSIGQUIT
eSIGTERM
viene ignorata.