2015-10-20 8 views
6

Ich habe ein Bash-Skript, das einen lang laufenden Prozess im Vordergrund läuft. Wenn es ein SIGQUIT-Signal empfängt, sollte es verschiedene Säuberungsvorgänge ausführen, wie das Töten von sich selbst und alle seine Kindprozesse (über das Löschen der Prozessgruppe usw.). Eine minimale Skript, welches das Signal fangen sollte, wird weiter unten (test_trap.sh genannt):Wie Trap zuverlässig mit Bash im Vordergrund Vordergrund Kind Prozesse verwenden

#!/bin/bash 

trap 'echo "TRAP CAUGHT"; exit 1' QUIT # other required signals are omitted for brevity 

echo starting sleep 
sleep 11666 
echo ending sleep 

echo done 

Ich möchte das SIGHUP Signal an den Prozess des test_trap.sh Skript senden. Das Senden eines SIGHUP an die test_trap.sh löst jedoch nicht den Trap-Ausdruck aus, sondern nur, wenn ich das Signal an das Kind sleep 11666 Prozess sendet, feuert die Falle. Nachfolgend finden Sie eine Sitzung bash dies demonstrieren:

bash-4.1$ test_trap.sh & 
[1] 19633 
bash-4.1$ starting sleep 

bash-4.1$ kill -s SIGQUIT 19633 
bash-4.1$ jobs 
[1]+ Running     test_trap.sh & 
bash-4.1$ ps -ef --forest --cols=10000 | grep '11666\|test_trap.sh' | grep -v grep 
theuser 19633 12227 0 07:40 pts/4 00:00:00    \_ /bin/bash ./test_trap.sh 
theuser 19634 19633 0 07:40 pts/4 00:00:00    | \_ sleep 11666 
bash-4.1$ kill -s SIGQUIT 19634 
bash-4.1$ Quit (core dumped) 
TRAP CAUGHT 

[1]+ Exit 1     test_trap.sh 
bash-4.1$ ps -ef --forest --cols=10000 | grep '11666\|test_trap.sh' | grep -v grep 
bash-4.1$ 

Beachten Sie, dass die „Schlaf 11666“ ist nur ein repräsentatives Verfahren. Dieser Prozess kann tatsächlich eine interaktive Subshell sein (z. B. bash -i).

Warum fängt der Elternprozess test_trap.sh nicht das SIGHUP-Signal ab? Warum sollte die Falle nur ausgelöst werden, wenn der Prozess für sleep 11666 gemeldet wurde?

Ich möchte nicht unkalkulierbare SIGKILL verwenden, da ich eine Auswahl von Bereinigungsoperationen im Trap-Ausdruck vornehmen muss.

Dieses Skript soll auf einer relativ aktuellen Version einer Linux-Distribution ausgeführt werden, die Bash enthält (z. B. nicht Cygwin).

Referenzen:

  1. killing Parent process along with child process using SIGKILL
  2. Kill bash and child process

Antwort

6

bash müssen warten, bis sleep abgeschlossen ist, bevor der Handler ausgeführt werden kann. Eine gute Problemumgehung besteht darin, sleep im Hintergrund auszuführen und dann sofort darauf zu warten. Während sleep unterbrechungsfrei ist, ist wait nicht.

trap 'kill $sleep_pid; echo "TRAP CAUGHT"; exit 1' QUIT 

echo starting sleep 
sleep 11666 & 
sleep_pid=$! 
wait 
echo ending sleep 

echo done 

Die Aufnahme von sleep_pid und dessen Verwendung sleep aus dem Handler zu töten sind optional.

+1

Ich muss dies als die Antwort markieren, da Sie meine Frage gestellt haben und es war sehr hilfreich. Ich sagte jedoch: "Dieser Prozess kann tatsächlich eine interaktive Subshell sein (z. B. bash -i)." Und ich hätte hinzufügen sollen: "Ich möchte den repräsentativen Prozess nicht in den Hintergrund stellen, weil er eine interaktive Shell sein könnte". – bgoodr

+0

Beachten Sie, dass der Benutzer der interaktiven Subshell trotzdem eigene Traps einrichten kann, um zu vermeiden, dass die Shell vom Aufrufer unterbrochen wird. – chepner

+0

@bgoodr haben Sie jemals eine Lösung gefunden, die den Prozess nicht in den Hintergrund stellt? – trex005

1

Eigentlich ist das Signal empfängt schlag, aber es ist in einem Zustand unterbrechungs für den sleep Befehl zu beenden wartet. Wenn es endet, wird Bash auf das Signal reagieren und die Falle ausführen.

Sie können den lange sleep Befehl mit einer Schleife von kurzen sleep Befehlen ersetzen:

while true 
do 
    sleep 1 
done 

Damit, wenn Sie das Signal an die bash zu senden, wird es, sobald der aktuell ausgeführten sleep Befehl reagieren endet, dh höchstens 1 Sekunde nach dem Senden.

+0

Vielen Dank, aber sehen Sie meine Antwort auf http://StackOverflow.com/Questions/33240221/How-To-use-Trap-reliably-using-bash-running-foreground-child-Processes#comment54286155_33241062 als Antwort @chepner die Antwort gegeben . Wenn Schlafen alles wäre, was ich tun wollte, dann würde Ihre Antwort ausreichen, aber das ist nur ein repräsentativer Prozess, den ich gerne im Vordergrund laufen ließe, da es sich dabei um einen interaktiven "Bash-i" -Prozess handeln könnte. – bgoodr

0

versuchen, mit dem Signal SIGINT (das gleiche, die durch Drücken von Strg + C gesendet wird) anstelle von SIGKILL. Andere Signale funktionieren nur, wenn die Bash E/A oder eine andere Bedingung verarbeiten kann.

Verwandte Themen