Möchten Sie diese Frage verbessern? Fügen Sie Details hinzu und klären Sie das Problem, indem Sie diesen Beitrag bearbeiten.
Vor 3 Jahren geschlossen.
Verbessern Sie diese Frage
Zum Verständnis
Wenn Bash auf die Ausführung eines Befehls wartet und ein Signal empfängt, für das
ein Trap gesetzt wurde, wird der Trap nicht ausgeführt, bis der
Befehl abgeschlossen ist.
Wenn Bash über das eingebaute Wait auf einen asynchronen Befehl wartet ,
der Empfang eines Signals, für das ein Trap gesetzt wurde, bewirkt, dass das
wait builtin sofort mit einem Exit-Status größer als
128 zurückkehrt, unmittelbar danach wird der Trap ausgeführt.
aus dem Bash-Handbuch
führe ich Folgendes aus:
-
In meinen beiden Beispielen beendet SIGINT (gesendet mit Strg-C) einen
Vordergrundjob (der erste Fall im Zitat) und einen Hintergrundjob
(der zweite Fall im Zitat) beide sofort, ohne zu warten damit
sie fertig werden.Bedeutet der erste Satz im Zitat, dass Bash einen
Vordergrundjob ausführt und das SignalSIGINTempfängt , die Falle des SignalsSIGINT, wenn gesetzt, wird ausgeführt, bis der Befehl abgeschlossen ist?
Wenn ja, warum in meinem ersten Beispielctrl-CSoll der Job im Vordergrund
existieren, bevor er abgeschlossen werden kann?$ sleep 10000 # a foreground job ^C $ sleep 10000 & # a background job [1] 21219 $ wait 21219 ^C $ echo $? 130 -
Was bedeutet “ein Signal, für das eine Falle gestellt wurde” meine,
-
ein Signal
argdessen Trap übertrap arg sigspecspezifiziert wurde , oder -
ein Signal, das nicht ignoriert wird, oder
-
ein Signal, dessen Trap nicht das Standard-Trap ist?
In den Beispielen in meinem Teil 1 habe ich keinen Trap für SIGINT eingerichtet, also hat das Signal seinen
Standard-Handler (der aus jeder ausgeführten Schleife ausbricht). Ist ein
Signal mit seinem Standard-Handler als eine Falle angesehen, die
aufgestellt wurde? -
-
Ich habe eine Falle für
SIGINTeingerichtet , aberctrl-Cbewirkt, dass der folgende
Befehl beendet wird, bevor er abgeschlossen wird. Widerspricht es also dem ersten
Satz in meinem Zitat?$ trap "echo You hit control-C!" INT $ bash -c 'sleep 10; echo "$?"' ^C $Vor dem Setzen des Trap für
SIGINT,ctrl-Cwird auch denselben
Befehl beenden, bevor er abgeschlossen ist. Widerspricht es also dem ersten
Satz in meinem Zitat?$ bash -c 'sleep 10; echo "$?"' ^C -
Können Sie einige Beispiele geben, um zu erklären, was die beiden Sätze in
dem Zitat bedeuten?
Danke.
Akzeptierte Antwort:
Was bedeutet „ein Signal, für das eine Falle gestellt wurde“?
Das ist ein Signal, für das ein Handler definiert wurde (mit trap 'handling code' SIG ), wobei der Bearbeitungscode nicht leer ist, da dies dazu führen würde, dass das Signal ignoriert wird.
Signale, die ihre Standarddisposition haben, sind also keine Signale, für die eine Falle gesetzt wurde.
Ein Teil dieses Zitats in Ihrem Beitrag gilt auch für Signale, die ihre Standarddisposition haben, obwohl offensichtlich nicht der Teil über das Ausführen der Falle , da für sie kein Trap definiert wurde.
Das Handbuch spricht über die Signalübermittlung an die Shell , nicht auf die Befehle, die Sie von dieser Shell aus ausführen.
1.
Wenn Bash auf die Ausführung eines Befehls wartet und ein Signal empfängt, für das ein Trap gesetzt wurde, wird der Trap nicht ausgeführt, bis der Befehl abgeschlossen ist.
(1)
Warum beendet Strg-C in meinem ersten Beispiel den Job im Vordergrund unmittelbar bevor er abgeschlossen werden kann
Wenn Sie sleep 10 ausführen an der Eingabeaufforderung einer interaktiven Shell , stellt die Shell diesen Job in den Vordergrund (durch ein ioctl() auf dem tty-Gerät, das der Terminalleitungsdisziplin mitteilt, welche Prozessgruppe die Vordergrundprozessgruppe ist), also nur sleep erhält ein SIGINT auf ^C und die interaktive Shell nicht , daher ist es nicht sinnvoll, dieses Verhalten zu testen.
-
Da die Eltern-Shell interaktiv ist, erhält sie das SIGINT nicht, da sich ihr Prozess nicht in der Vordergrundprozessgruppe befindet.
-
Jedem Befehl steht es frei, Signale nach Belieben zu behandeln.
sleepmacht nichts besonderes mit SIGINT, erhält also die Standarddisposition (beenden), es sei denn, SIGINT wurde beim Start ignoriert.
(2) Wenn Sie sleep 10 ausführen in einer nicht interaktiven Shell ,
bash -c 'sleep 10; echo "$?"'
Sowohl die nicht interaktive bash Shell und sleep erhält das SIGINT, wenn Sie Strg-C drücken.
Wenn bash sofort beendet, könnte es den sleep verlassen Befehl, der unbeaufsichtigt im Hintergrund ausgeführt wird, wenn er das SIGINT-Signal ignoriert oder verarbeitet. Also stattdessen
bashwie die meisten anderen Shells, Blöcke der Empfang von Signalen (zumindest einiger Signale) beim Warten auf Befehle.- Die Lieferung wird fortgesetzt, nachdem der Befehl beendet wurde (wobei Traps ausgeführt werden). Das vermeidet auch, dass Befehle in Traps gleichzeitig mit anderen Befehlen ausgeführt werden.
In diesem Beispiel oben sleep stirbt bei SIGINT, also bash muss nicht lange warten, um mit seinem eigenen SIGINT fertig zu werden (hier um zu sterben, da ich keine trap hinzugefügt habe auf SIGINT).
(3) wenn Sie Strg+C drücken, während Sie die nicht interaktive Shell ausführen:
bash -c 'sh -c "trap "" INT; sleep 3"; echo "$?"'
(ohne trap auf SIGINT) bash wird nicht durch das SIGINT getötet. bash , behandeln wie einige andere Shells SIGINT und SIGQUIT speziell. Sie implementieren den Warten und kooperativen Ausgang Verhalten, das unter https://www.cons.org/cracauer/sigint.html beschrieben wird (und ist dafür bekannt, einige Ärgernisse zu verursachen, wie die Skripte, die SIGINT-Handhabungsbefehle aufrufen, die nicht mit ^C unterbrochen werden können )
(4) Um richtig zu testen, sollten Sie eine nicht-interaktive bash ausführen das ein SIGINT-Trap-Set hat und ruft einen Befehl auf, der bei SIGINT nicht sofort stirbt wie:
bash -c 'trap "echo Ouch" INT; sh -c "trap "" INT; sleep 3"'
bash wartet auf sh das hat (zusammen mit sleep ) SIGINT ignoriert (wegen trap "" INT ), sodass SIGINT sleep nicht beendet noch sh . bash ignoriert SIGINT nicht, aber seine Behandlung wird aufgeschoben bis sh kehrt zurück. Sie sehen Ouch angezeigt wird, nicht bei Strg+C , aber nach sleep und sh wurden normal beendet.
Beachten Sie, dass die trap Der Befehl setzt eine Falle für ein Signal für dieselbe Shell, in der er ausgeführt wird. Also, wenn die trap Der Befehl wird außerhalb der nicht interaktiven Shell und in der übergeordneten Shell ausgeführt,
$ trap "echo You hit control-C!" INT $ bash -c 'sleep 10; echo "$?"' ^C $
die nicht interaktive bash , und sleep Befehle erben diesen trap nicht aus der Elternschale. Signal-Handler gehen verloren, wenn ein anderer Befehl ausgeführt wird (execve() löscht den gesamten Adressraum des Prozesses einschließlich des Codes des Handlers). Nach execve() , Signale, für die ein Handler definiert wurde, werden auf die Standarddisposition zurückgesetzt, diejenigen, die ignoriert wurden, bleiben ignoriert.
Darüber hinaus ist in den meisten Shells trap s werden auch in Sub-Shells zurückgesetzt.
2.
Wenn Bash über das eingebaute Wait auf einen asynchronen Befehl wartet , führt der Empfang eines Signals, für das ein Trap gesetzt wurde, dazu, dass das Wait-Built sofort mit einem Exit-Status größer als 128 zurückkehrt, woraufhin das Trap sofort ausgeführt wird.
Bei Verwendung von wait ausdrücklich , wait wird durch jedes Signal unterbrochen, das einen Fallensatz hat (und natürlich auch solche, die die Shell vollständig töten).
Das macht es schwierig, den Ausgangsstatus eines Befehls zuverlässig abzurufen, wenn es eingefangene Signale gibt :
$ bash -c 'trap "echo Ouch" INT; sh -c "trap "" INT; sleep 10" & wait "$!"; echo "$?"'
^COuch
130
In diesem Fall sleep und sh wurden nicht vom SIGINT getötet (da sie es ignorieren). Immer noch wait kehrt mit einem 130 zurück Exit-Status, weil ein Signal (SIGINT) empfangen wurde, während auf sh gewartet wurde . Sie müssen das wait "$!" wiederholen bis sh wirklich beendet, um sh zu erhalten Exit-Status.