(Ispirato dalla risposta di Gilles)
Con il ISIGflag impostato, l'unico modo per Childottenere lo script SIGINTsenza il suo genitore SIGINTè che sia nel suo gruppo di processi. Questo può essere realizzato con l' set -mopzione.
Se si attiva l' -mopzione nello Childscript 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 SIGINTquando il INTRpersonaggio viene letto.
Ecco la descrizione POSIX -mdell'opzione :
-mQuesta 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' -mopzione è simile a -i, ma non altera il comportamento della shell quasi quanto -ifa.
Esempio:
la Parentsceneggiatura:
#!/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 Childsceneggiatura:
#!/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 SIGINTgestore del genitore non viene mai eseguito.
In alternativa, se preferisci modificare Parentinvece di Child, puoi farlo:
la Parentsceneggiatura:
#!/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 Childscript (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
SIGINTper la durata di Child. Questo non risponde alla tua domanda, ma può darti quello che vuoi.
- Modifica
Childper:
- Utilizzare
stty -gper eseguire il backup delle impostazioni correnti del terminale.
- Eseguire
stty -isigper non generare segnali con i INTR, QUITe SUSPcaratteri.
- Nei precedenti, leggere l'input terminale e inviare i segnali stessi come appropriato (ad esempio, eseguire
kill -QUIT 0quando Control+ \viene letto, kill -INT $$quando Control+ Cviene letto). Questo non è banale e potrebbe non essere possibile farlo funzionare senza problemi se lo Childscript 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 setpgidutility 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 erroreSIGQUITeSIGTERMviene ignorata.