GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Warum wird der Vordergrundjob bei der Eingabe von Strg-c in einem Terminal nicht beendet, bis er abgeschlossen ist?

Geschlossen . Diese Frage braucht Details oder Klarheit. Antworten werden derzeit nicht akzeptiert.

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:

  1. 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 Signal SIGINT empfängt , die Falle des Signals
    SIGINT , wenn gesetzt, wird ausgeführt, bis der Befehl abgeschlossen ist?
    Wenn ja, warum in meinem ersten Beispiel ctrl-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
    
  2. Was bedeutet “ein Signal, für das eine Falle gestellt wurde” meine,

    • ein Signal arg dessen Trap über trap 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?

  3. Ich habe eine Falle für SIGINT eingerichtet , aber ctrl-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
    
  4. 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.

Verwandte:Linux – Erhöhen Sie die Lautstärke eines MKV-Videos vom Linux-Terminal?

(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).

Verwandte:Wie kann man eine Partition schnell in ein Dateisystem formatieren?

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.


Linux
  1. Warum wird die Bash-Eingabeaufforderung fehlerhaft, wenn ich den Verlauf durchsuche?

  2. Warum (und wie) hat die Verwendung von Cat auf Binärdateien das Terminal durcheinander gebracht?

  3. Warum wacht der Bildschirmschoner bei der Verwendung von Vlc immer wieder auf?

  4. Warum speichert der dauerhafte Iptables-Dienst die Änderungen nicht?

  5. Wie konfiguriere ich Bashrc so, dass alle Tmux-Sitzungen geschlossen werden, wenn ich das Terminal schließe?

Warum ich Alpine immer noch für E-Mail am Linux-Terminal liebe

Bash-insulter – Ein Skript, das den Benutzer beleidigt, wenn er einen falschen Befehl eingibt

Wann wird ein Signal behandelt und warum frieren einige Informationen ein?

Warum wird eine Bash-While-Schleife nicht beendet, wenn sie zu einem beendeten Unterbefehl weitergeleitet wird?

Warum kann ich im Terminal nicht scrollen?

Wann sendet das System ein SIGTERM an einen Prozess?