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 SignalSIGINT
empfängt , die Falle des SignalsSIGINT
, wenn gesetzt, wird ausgeführt, bis der Befehl abgeschlossen ist?
Wenn ja, warum in meinem ersten Beispielctrl-C
Soll 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
arg
dessen Trap übertrap arg sigspec
spezifiziert 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
SIGINT
eingerichtet , aberctrl-C
bewirkt, 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-C
wird 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.
sleep
macht 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
bash
wie 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.