(Inspiriert von Gilles 'Antwort)
Wenn das ISIGFlag gesetzt ist, kann das ChildSkript nur dann abrufen, wenn es SIGINTübergeordnet SIGINTist, wenn es sich in einer eigenen Prozessgruppe befindet. Dies kann mit der set -mOption erreicht werden.
Wenn Sie die -mOption im ChildShell-Skript aktivieren, wird die Jobsteuerung ausgeführt, ohne interaktiv zu sein. Dies führt dazu, dass Dinge in einer separaten Prozessgruppe ausgeführt werden, wodurch verhindert wird, dass das übergeordnete Element das empfängt, SIGINTwenn das INTRZeichen gelesen wird.
Hier ist die POSIX-Beschreibung der -mOption :
-mDiese Option wird unterstützt, wenn die Implementierung die Option User Portability Utilities unterstützt. Alle Jobs sollen in eigenen Prozessgruppen ausgeführt werden. Unmittelbar bevor die Shell nach Abschluss des Hintergrundjobs eine Eingabeaufforderung ausgibt, wird eine Nachricht, die den Beendigungsstatus des Hintergrundjobs meldet, in den Standardfehler geschrieben. Wenn ein Vordergrundjob angehalten wird, schreibt die Shell eine entsprechende Nachricht mit Standardfehler, die wie vom Jobdienstprogramm beschrieben formatiert ist. Wenn ein Job einen anderen Status als das Beenden ändert (z. B. wenn er für die Eingabe oder Ausgabe stoppt oder durch ein SIGSTOP-Signal gestoppt wird), muss die Shell unmittelbar vor dem Schreiben der nächsten Eingabeaufforderung eine ähnliche Nachricht schreiben. Diese Option ist standardmäßig für interaktive Shells aktiviert.
Die -mOption ähnelt -i, ändert jedoch das Verhalten der Shell nicht annähernd so stark wie -isie.
Beispiel:
das ParentSkript:
#!/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"
das ChildSkript:
#!/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"
Dies passiert, wenn Sie Control+ drücken, Cwährend Sie Childauf die Eingabe warten:
$ ./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
Beachten Sie, dass der SIGINTHandler des Elternteils niemals ausgeführt wird.
Wenn Sie Parentstattdessen lieber ändern möchten Child, können Sie dies alternativ tun:
das ParentSkript:
#!/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"
das ChildSkript (normal; keine Notwendigkeit -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"
Alternative Ideen
- Ändern Sie die anderen Prozesse in der Vordergrundprozessgruppe, um sie
SIGINTfür die Dauer von zu ignorieren Child. Damit wird Ihre Frage nicht beantwortet, aber Sie erhalten möglicherweise das, was Sie möchten.
- Ändern
Childzu:
- Verwenden Sie
stty -gdiese Option, um die aktuellen Terminaleinstellungen zu sichern.
- Führen Sie
stty -isignicht erzeugen Signale mit den INTR, QUITund SUSPZeichen.
- Lesen Sie im Hintergrund den Terminaleingang und senden Sie die Signale gegebenenfalls selbst (z. B. ausführen,
kill -QUIT 0wenn Control+ \gelesen wird, kill -INT $$wenn Control+ Cgelesen wird). Dies ist nicht trivial und es ist möglicherweise nicht möglich, dass dies reibungslos funktioniert, wenn das ChildSkript oder etwas, das es ausführt, interaktiv sein soll.
- Stellen Sie die Terminaleinstellungen vor dem Beenden wieder her (idealerweise ab einer Falle
EXIT).
- Wie # 2 mit der Ausnahme , anstatt läuft
stty -isig, Warten auf den Benutzer Hit Enteroder einem anderen Nicht-Spezialschlüssel vor der Tötung Child.
Schreiben Sie Ihr eigenes setpgidDienstprogramm in C, Python, Perl usw., das Sie zum Aufrufen verwenden können setpgid(). Hier ist eine grobe C-Implementierung:
#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;
}
Anwendungsbeispiel von 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). Beispiele:${ENV}Wird bezogen, wird die Shell nicht sofort beendet, wenn ein Fehler auftritt,SIGQUITundSIGTERMwird ignoriert.