Ignoriere das HUP-Signal im Bash-Skript mit Pipe-Befehlen

8

Ich habe das folgende Skript, das das Verzeichnis /tmp auf unbestimmte Zeit überwacht und wenn es irgendwelche Operationen mit Dateien in diesem Verzeichnis gibt, wird der Dateiname von while loop gelesen und das erste a -Zeichen im Dateinamen wird durch% co_de ersetzt % Zeichen und dieser geänderte Dateiname wird in b file:

protokolliert %Vor%

Dies ist eine vereinfachte Version des eigentlichen Skripts. Ich habe auch ein Sys-V-Typ-Init-Skript für das obige Skript und da ich LSB-kompatibel bleiben möchte, hat mein Init-Skript test.log ( bewirkt, dass die Konfiguration neu geladen wird, wenn der Dienst dies unterstützt Dienst wird neu gestartet. ) Option, die das HUP-Signal an Skript sendet. Vor der Ausführung von force-reload , die force-reload ausführt, folgt die Ausgabe von killproc -HUP test.sh :

%Vor%

Nach der Ausführung von pstree wird die untergeordnete Shell beendet:

%Vor%

Laut strace killproc -HUP test.sh , strace send killproc an die Prozesse SIGHUP und 4424 , aber nur letzteres wurde beendet.

Was ist der Sinn dieser Kind-Shell mit PID 4426 in meinem Beispiel, d. h. warum wird sie überhaupt erstellt? Gibt es außerdem eine Möglichkeit, 4426 signal zu ignorieren?

    
Martin 08.12.2015, 17:42
quelle

1 Antwort

8

Pipeline-Befehle werden in einer Subshell

ausgeführt

Der erste Teil Ihrer Frage wird durch den Mechanismus erklärt, durch den eine Shell (in diesem Fall Bash) Befehle in einer Pipeline ausführt.

Ein pipe ist ein FIFO (first in, first out) einseitiger IPC-Kanal (interprocess communication): Er ermöglicht das Schreiben von Bytes an einem Ende (das schreibgeschützte Ende ) und das Lesen vom anderen ( schreibgeschütztes Ende ), ohne dass ein physisches Dateisystem gelesen oder in ein physisches Dateisystem geschrieben werden muss.

Eine Pipeline ermöglicht zwei verschiedene Befehle über einen anonymen oder unbenannten (dh hat keinen Eintrag im Dateisystem) zu kommunizieren. Rohr.

Wenn ein einfacher Befehl von einer Shell ausgeführt wird, wird der Befehl in einem untergeordneten Prozess der Shell ausgeführt. Wenn keine Jobsteuerung verwendet wird, wird die Kontrolle über das Terminal von der Shell wiedergewonnen, wenn der Kindprozess beendet wird.

Wenn zwei Befehle in einer Pipeline ausgeführt werden, werden beide Befehle in der Pipeline als zwei separate untergeordnete Prozesse ausgeführt, die gleichzeitig ausgeführt werden.

In Unix-Systemen werden Pipes mit dem Systemaufruf pipe(2) erstellt, der eine neue Pipe erstellt und ein Dateideskriptorpaar zurückgibt, wobei sich eines auf das Ende und das andere auf schreibe Ende der Pipe.

Mit Bash auf einem GNU / Linux-System wird der Systemaufruf clone(2) zum Erstellen der Teilprozesse verwendet. Dadurch kann der untergeordnete Prozess die Tabelle der Dateideskriptoren mit seinem übergeordneten Prozess teilen, so dass beide untergeordneten Unterprozesse den Dateideskriptor der anonymen Pipe erben, sodass der eine darauf lesen kann und der andere schreiben kann dazu.

In Ihrem Fall erhält der Befehl inotifywait eine PID von 4425 und schreibt auf das schreibgeschützte Ende der Pipe, indem er seine stdout mit dem Dateideskriptor des Schreibendes verbindet.

Zur gleichen Zeit erhält die rechte Seite des Pipe-Befehls die PID, 4426, und ihr stdin -Dateideskriptor wird auf den des schreibgeschützten Endes der Pipe gesetzt. Da die Subshell für die rechte Seite der Pipe kein externer Befehl ist, entspricht der Name für den untergeordneten Prozess dem des übergeordneten Elements test.sh .

Weitere Informationen finden Sie unter man 7 pipe und den folgenden Links:

Signalbehandlung

Es hat mich eine Ewigkeit gekostet (ein paar Stunden Recherche), um herauszufinden, warum die Falle für das SIGHUP-Signal nicht ignoriert wurde.

Alle meine Nachforschungen haben ergeben, dass ein Kindprozess, der durch einen clone(2) Systemaufruf erstellt wurde, auch in der Lage sein sollte, die Tabelle der Signalbehandlungsroutinen des Elternprozesses zu teilen.

Die Bash-Manpage gibt auch an, dass

  

Befehlsersetzungen, Befehle, die in Klammern gruppiert sind, und asynchrone Befehle werden in einer Subshell-Umgebung aufgerufen, die ein Duplikat der Shellumgebung ist. Die von der Shell abgefangenen Traps werden jedoch auf die Werte zurückgesetzt, die die Shell von ihrem übergeordneten Objekt geerbt hat .

Später heißt es das

  

Signale, die beim Eintritt in die Shell ignoriert werden, können nicht abgefangen oder zurückgesetzt werden. Eingeschlossene Signale, die nicht ignoriert werden, werden in einer Subshell- oder Subshell-Umgebung auf ihre ursprünglichen Werte zurückgesetzt, wenn eine erstellt wird.

Dies bedeutet, dass Subshells keine Signalhandler erben, die nicht ignoriert sind. So wie ich es verstanden habe, bedeutete Ihre trap ':' HUP -Zeile, dass das SIGHUP-Signal (effektiv) ignoriert wurde (da das : builtin nur den Erfolg zurückliefert) - und sollte wiederum von der Subshell der Pipeline ignoriert werden.

Allerdings stieß ich irgendwann auf die Beschreibung von trap in der Bash-Manpage, die definiert, was Bash mit ignorieren meint:

  

Wenn arg der Null-String ist, wird das von jedem sigspec angegebene Signal von der Shell und den von ihr aufgerufenen Befehlen ignoriert.

Durch einfaches Ändern des Befehls trap in trap '' HUP wird sichergestellt, dass das SIGHUP-Signal für das Skript selbst - und alle Unterschellen ignoriert wird.

    
Anthony Geoghegan 08.12.2015, 23:30
quelle

Tags und Links