17 Stimmen

Beendet laufende Befehle, wenn das Shell-Skript beendet wird

Zu Testzwecken habe ich dieses Shell-Skript

#!/bin/bash
echo $$
find / >/dev/null 2>&1

Wenn Sie dies von einem interaktiven Terminal aus ausführen, beendet ctrl+c die Bash und den Befehl find.

$ ./test-k.sh
13227
<Ctrl+C>
$ ps -ef |grep find
$

Wenn Sie das Skript im Hintergrund ausführen und nur die Shell beenden, werden die im Skript ausgeführten Befehle verwaist sein.

$ ./test-k.sh &
[1] 13231
13231
$ kill 13231
$ ps -ef |grep find
nos 13232     1  3 17:09 pts/5    00:00:00 find /
$

Ich möchte, dass dieses Shell-Skript alle untergeordneten Prozesse beendet, wenn es beendet wird, unabhängig davon, wie es aufgerufen wird. Es wird schließlich von einer Python und Java-Anwendung gestartet werden - und irgendeine Form der Bereinigung ist erforderlich, wenn das Skript beendet - alle Optionen, die ich in oder irgendeine Möglichkeit, das Skript umschreiben, um sich beim Beenden zu bereinigen aussehen sollte?

15voto

Carl Norum Punkte 210051

Ich würde etwa so vorgehen:

#!/bin/bash
trap : SIGTERM SIGINT

echo $$

find / >/dev/null 2>&1 &
FIND_PID=$!

wait $FIND_PID

if [[ $? -gt 128 ]]
then
    kill $FIND_PID
fi

Ich denke, eine Erklärung ist angebracht. Zunächst müssen wir einige der Standard-Signalverarbeitung ändern. : ist ein No-op-Befehl, da die Übergabe einer leeren Zeichenkette die Shell veranlasst, das Signal zu ignorieren, anstatt etwas dagegen zu unternehmen (das Gegenteil von dem, was wir tun wollen).

Dann wird die find wird im Hintergrund ausgeführt (aus Sicht des Skripts) und wir rufen die wait eingebaut, um es zu beenden. Da wir einen echten Befehl an trap oben, wenn ein Signal behandelt wird, wait wird mit einem Status größer als 128 beendet. Wenn der Prozess wait für vervollständigt, wait gibt den Exit-Status des Prozesses zurück.

Zuletzt, wenn die wait diesen Fehlerstatus zurückgibt, wollen wir kill den Kindprozess. Glücklicherweise haben wir seine PID gespeichert. Der Vorteil dieses Ansatzes ist, dass Sie eine Fehlermeldung protokollieren oder auf andere Weise feststellen können, dass ein Signal das Skript beendet hat.

Wie andere bereits erwähnt haben, ist die kill -- -$$ als Ihr Argument für trap ist eine weitere Option, wenn Sie keine Informationen nach dem Verlassen der Website hinterlassen wollen.

Pour trap so zu funktionieren, wie Sie es wünschen, müssen Sie es mit wait - die bash Manpage sagt: "Wenn bash auf die Fertigstellung eines Befehls wartet und ein Signal empfängt, für das ein trap gesetzt wurde, wird die trap wird nicht ausgeführt, bis der Befehl abgeschlossen ist." wait ist der Weg, dieses Problem zu umgehen.

Sie können diese Funktion auch auf weitere untergeordnete Prozesse ausdehnen, wenn Sie dies wünschen. Ich habe das nicht wirklich ausgiebig getestet, aber es scheint hier zu funktionieren.

$ ./test-k.sh &
[1] 12810
12810
$ kill 12810
$ ps -ef | grep find
$

9voto

phemmer Punkte 5433

Ich suchte nach einer eleganten Lösung für dieses Problem und fand an anderer Stelle die folgende Lösung.

trap 'kill -HUP 0' EXIT

Meine eigenen Seiten sagen nichts darüber aus, was 0 bedeutet, aber wenn man sich umschaut, scheint es die aktuelle Prozessgruppe zu meinen. Da das Skript seine eigene Prozessgruppe erhält, wird SIGHUP an alle Kinder des Skripts gesendet, sowohl im Vordergrund als auch im Hintergrund.

6voto

pixelbeat Punkte 28985

Senden Sie ein Signal an die Gruppe. Also statt kill 13231 tun:

kill -- -13231

Wenn Sie mit Python anfangen, dann schauen Sie sich das an: http://www.pixelbeat.org/libs/subProcess.py die zeigt, wie man die Shell beim Starten und Töten einer Gruppe

3voto

teh_senaus Punkte 1327

Die Antwort von @Patrick hat fast geholfen, aber sie funktioniert nicht, wenn die Elternteil Prozess Ihrer aktuell Shell ist in der gleichen Gruppe (sie tötet auch das Elternteil).

Ich fand das besser:

trap 'pkill -P $$' EXIT

Siehe aquí für weitere Informationen.

1voto

Vlad the Impala Punkte 14862

Fügen Sie einfach eine Zeile wie diese in Ihr Skript ein:

trap "kill $$" SIGINT

Möglicherweise müssen Sie "SIGINT" in "INT" ändern, aber das wird Ihren Prozess und alle Kindprozesse beenden, wenn Sie Strg-C drücken.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X