Wie kann ich ein Skript beenden, das im Terminal ausgeführt wird, ohne das Terminal zu schließen (Strg + C funktioniert nicht)?

35

Ich habe ein Bash-Skript geschrieben, das mehrere andere Programme aufruft und eine Reihe von Befehlen ausführt. Ich führe dieses Skript vom Terminal aus. Jetzt möchte ich das Drehbuch töten.

Das Drücken von Ctrl + Cschneidet manchmal nicht ab, weil das Skript manchmal ein anderes Programm ausführt und aus irgendeinem Grund das Kill-Signal nicht funktioniert.

Wenn ich jedoch das Terminalfenster schließe, wird das Skript beendet.

Kann ich etwas tun (eine Tastenkombination), das dem Schließen des Terminalfensters entspricht, ohne das Terminalfenster tatsächlich zu schließen (ich möchte den Befehlsverlauf, das aktuelle Verzeichnis, den Ausgabeverlauf usw. nicht verlieren)?

becko
quelle
8
In solchen Fällen versuche ichCtrl + z
kenn
Und nach dem Ctrl + zLauf:kill -9 $(pgrep -f your_script.sh)
Noam Manos

Antworten:

38

Sie haben nur wenige Möglichkeiten. Eine besteht darin, das Skript zu stoppen ( CtrlZ), die PID des Skripts abzurufen und SIGKILLan die Prozessgruppe zu senden .

Wenn ein Befehl in einer Shell ausgeführt wird, ist der Prozess, den er startet, und alle untergeordneten Prozesse Teil derselben Prozessgruppe (in diesem Fall der Vordergrundprozessgruppe). Um ein Signal an alle Prozesse in dieser Gruppe zu senden, senden Sie es an den Prozessleiter. Für den killBefehl wird der Prozessleiter folgendermaßen bezeichnet:

kill -PID

Wo PIDist die Prozess-ID des Skripts?

Beispiel:

Stellen Sie sich ein Skript vor, test.shdas einige Prozesse startet. Angenommen, Sie haben es in einer Shell ausgeführt:

$ ./test.sh

In einem anderen Terminal,

$ pgrep test.sh
17802
$ pstree -ps `!!`
pstree -ps `pgrep test.sh`
init(1)───sshd(1211)───sshd(17312)───sshd(17372)───zsh(17788)───test.sh(17802)─┬─dd(17804)
                                                                               ├─sleep(17805)
                                                                               └─yes(17803)

In diesem Fall führen test.shSie die folgenden Schritte aus , um ein Signal an die von erstellte Prozessgruppe zu senden :

kill -INT -17802

-INTwird zum Senden verwendet SIGINT. Dieser Befehl entspricht dem Drücken CtrlCauf das Terminal. Zu senden SIGKILL:

kill -KILL -17802

Sie müssen das Skript nur anhalten, wenn Sie kein anderes Terminal öffnen können. Wenn Sie können, verwenden Sie pgrep, um die PID zu finden.

Einer der Befehle, die das Skript startet, ist möglicherweise ein Überfüllungsbefehl. Dies SIGINTist wahrscheinlich der Grund, warum er CtrlCunwirksam ist. Allerdings SIGKILLkann nicht gefangen werden, und es ist in der Regel eine letztinstanzliche Option. Möglicherweise möchten Sie versuchen SIGTERM( -TERM), bevor Sie für die Tötung gehen. Weder SIGKILLoder SIGTERMkann so eingerichtet werden , wie eine Tastenkombination die Art und Weise SIGINTist.

All dies ist umstritten, wenn Ihr Skript keine Shebang-Zeile enthält. Aus dieser SO Antwort :

Normalerweise vermutet die übergeordnete Shell, dass das Skript für dieselbe Shell geschrieben wurde (minimale Bourne-ähnliche Shells führen das Skript mit / bin / sh aus, bash führt es als bash-Unterprozess aus) ...

Aus diesem Grund finden Sie bei der Ausführung des Skripts keinen nach Skript benannten Prozess (oder einen Prozess mit dem Namen des Skripts in der Befehlszeile) und pgrepschlagen fehl.

Verwenden Sie immer eine Shebang-Schnur.

muru
quelle
Gibt es eine Tastaturkombination für SIGKILLoder SIGTERM?
Becko
@becko Nein, und Sie können nicht einrichten ein: superuser.com/a/417991/334516
muru
pgrep test.shgibt die PID nicht für mich zurück. Ich habe versucht , eine einfache test.sh: for i in {1..30}; do sleep 1 echo $i done Während test.shausgeführt wird , führe ich pgrep test.shin einem anderen Terminal, aber nichts zurückgegeben. Was ist falsch?
Becko
1
@becko wie hast du das script ausgeführt? Versuchen Sie es auch pgrep -f test.sh.
muru
pgrep -f test.shfunktioniert auch nicht. Ich ./test.sh
starte
6

Wenn Sie die Prozesse kennen, die mit dem Skript verknüpft sind, können Sie deren PID mithilfe von ermitteln

 ps -A

und verwenden Sie dann die PID-Nummer, um die entsprechenden Prozesse mit abzubrechen

 kill -9 PID_Number
Harris
quelle
1
Das ist zu kompliziert. Das Skript erzeugt mehrere andere Programme, und diese Programme erzeugen auch parallele Prozesse. Es ist sehr schwer, all diese Prozesse im Auge zu behalten. Es muss eine einfachere Lösung geben, ähnlich wie beim Schließen des Terminalfensters.
Becko
Können Sie versuchen, pkill-P $$
Harris
1

Wie Harris sagte, können Sie Kill -9 PID_Numberdas Paket ausführen, aber Sie können es auch installieren htop, um einen interaktiven Prozessbrowser zu haben, der das Auffinden bestimmter Prozesse erheblich erleichtert. htop unterstützt auch Tötungsprozesse.

Schlafentzogener Bulbasaur
quelle