Wie stoppe ich das Loop-Bash-Skript im Terminal?

54

Zum Beispiel,

#!/bin/bash
while :
do
    sl
done

Wie kann ich dieses Bash-Skript beenden?

Yinyanghu
quelle
1
Geben Sie weitere Details an. Möchten Sie es interaktiv oder programmgesteuert stoppen?
Manatwork
1
Sie können drücken ctrl-c, um das SIGINTSignal zu senden (in den meisten Shells), oder Sie können drücken ctrl-z, um das Signal zu senden (in den SIGTSTPmeisten Shells). In dem Fall, dass Sie gedrückt haben, wird ctrl-zder zugehörige Prozess nicht abgebrochen, sondern angehalten. Sie können es mit fg(mindestens in bash)
user1146332
Nein, das geht nicht!
Yinyanghu
4
Das Problem ist nicht das Skript, sondern der slBefehl, den ich für ärgerlich halte, wenn man falsch schreibt lsund einen Zug zeigt, der langsam vorbeifährt. Soweit ich weiß, fängt es das SIGINTSignal ab und muss mit getötet werden SIGKILL.
1
Vielen Dank. Nicht für meine Distribution gepackt, deshalb habe ich es nicht gewusst / gefunden. (Ich glaube, ich werde keinen Antrag dafür stellen.)
manatwork

Antworten:

64

Das Programm slignoriert absichtlich SIGINT, was gesendet wird, wenn Sie drücken Ctrl+C. Zunächst müssen Sie also durch Hinzufügen des Arguments angeben, dass Sie slnicht ignorieren sollen .SIGINT-e

Wenn Sie dies versuchen, werden Sie feststellen, dass Sie jeden einzelnen stoppen können sl, aber sie wiederholen sich immer noch. Sie müssen sagen bash, dass Sie auch nach beenden müssen SIGINT. Sie können dies tun, indem Sie ein trap "exit" INTvor die Schleife setzen.

#!/bin/bash
trap "exit" INT
while :
do
    sl -e
done
Jim Paris
quelle
5
Ich habe es nicht installiert, um zu überprüfen, aber Sie können es möglicherweise auch mit SIGQUIT von Ctrl- \
derobert
120
  1. Drücken Sie Ctrl-Z, um das Skript anzuhalten
  2. kill %%

Das %%teilt der integrierten Bash mit, killdass Sie ein Signal (standardmäßig SIGTERM) an den zuletzt angehaltenen Hintergrundjob in der aktuellen Shell und nicht an eine Prozess-ID senden möchten.

Sie können Jobs auch nach Nummer oder nach Name angeben. Wenn Sie z. B. einen Job mit ^ Z anhalten, werden Sie von bash über die Jobnummer informiert [n]+ Stopped, wobei nin den eckigen Klammern die Jobnummer steht.

Für weitere Informationen über Auftragssteuerung und zu töten , Jobs, laufen help jobs, help fg, help bg, und help killin bash, und die Suche nach JOB CONTROL(alle Caps) oder jobspecin der bash man - Seite.

z.B

$ ./killme.sh 
./killme.sh: Zeile 4: sl: Befehl nicht gefunden
./killme.sh: Zeile 4: sl: Befehl nicht gefunden
./killme.sh: Zeile 4: sl: Befehl nicht gefunden
./killme.sh: Zeile 4: sl: Befehl nicht gefunden
./killme.sh: Zeile 4: sl: Befehl nicht gefunden
...
...
...
./killme.sh: Zeile 4: sl: Befehl nicht gefunden
^ Z
[1] + Gestoppt ./killme.sh
$ kill %%
$ 
[1] + Beendet ./killme.sh

In diesem Beispiel war die Jobnummer 1, kill %1hätte also genauso funktioniert wiekill %%

(ANMERKUNG: Ich habe nicht slinstalliert, so dass die Ausgabe nur "Befehl nicht gefunden" ist. In Ihrem Fall erhalten Sie die Ausgabe, die sl erzeugt. Es ist nicht wichtig - das ^ZAnhalten und kill %%wird genauso funktionieren.)

cas
quelle
3
Noch eine gute Antwort!
Yinyanghu,
2
Übrigens, um solche Schleifen schnell auszuführen, kann ^ Z eine zuverlässigere Methode sein, um den Prozess abzubrechen als ^ C. ^ C wird an das Programm ( sl) gesendet, das in der Schleife ausgeführt wird, aber das Skript läuft weiter ... und startet ein anderes sl. Wenn Sie ^ C einige Male sehr schnell drücken, können Sie möglicherweise sowohl sldas Skript als auch das Skript beenden (wenn keines von beiden SIGINT abfängt). ^ Z unterbricht das Skript fast sofort (sofort, wenn Sie keine gepufferten Ausgaben zählen, die noch auf Ihrem Terminal gedruckt werden), sodass Sie es mitkill %%
cas
Genau! Ich muss sagen " slist ein lustiges Programm". Diesmal macht es mir wieder Spaß! @ _ @
Yinyanghu
Nur eine Antwort, die auch zu funktionieren scheint, wenn die Schleife nicht von einem Skript, sondern direkt von der Kommandozeile aufgerufen wird.
Skippy le Grand Gourou
1
@DrewChapin Ich kann mich nicht erinnern, wann / wo ich davon erfahren habe - nur etwas, das ich "seit Ewigkeiten" kenne. Die Bash-Manpage (Suche nach Jobspec ) sagt:The symbols %% and %+ refer to the shell's notion of the current job, which is the last job stopped while it was in the foreground or started in the background. The previous job may be referenced using %-. If there is only a single job, %+ and %- can both be used to refer to that job
cas
6

Wenn Sie möchten, dass Strg + C die Schleife stoppt, das Skript jedoch nicht beendet, können Sie || breaknach jedem Befehl, den Sie ausführen, einen Befehl einfügen . Solange das von Ihnen ausgeführte Programm mit Strg + C beendet wird, funktioniert dies hervorragend.

#!/bin/bash
while :
do
    # ctrl+c terminates sl, but not the shell script
    sl -e || break
done

Wenn Sie sich in einer verschachtelten Schleife befinden, können Sie "break 2" verwenden, um zwei Ebenen usw. zu verlassen.

Dale Anderson
quelle
plus 1 für Pause 2
Flyingfinger
3

Sie können dieses Skript beenden, indem Sie in dem Terminal, in dem Sie dieses Skript gestartet haben, Strg + C drücken. Natürlich muss dieses Skript im Vordergrund laufen, damit Sie es mit Strg + C stoppen können.

Oder Sie können die PID (Prozess-ID) dieses Skripts in einem anderen geöffneten Terminal finden, indem Sie:

ps -ef | grep <name_of_the_script>
kill -9 <pid_of_your_running_script>

Beide Wege sollten den Trick tun, nach dem Sie fragen.

panaroik
quelle
1
Es kann nicht mit Strg + C vom Terminal beendet werden. Also muss ich es mit ps oder top töten. Ich möchte nur wissen, wie man es direkt tötet!
Yinyanghu
3

Am einfachsten ist es, das QUITSignal auszugeben, an das normalerweise angehängt wird Control-Backslash.

Wenn Sie den Zug sehen, drücken Sie Strg- \

RobertL
quelle
1

Sie können killdie pidShell (Bash).
Ich habe es gerade versucht und es funktioniert.
Weil ich den Prozess von ps -ef(dem Job, den wir im Schleifenskript ausführen) nicht sehen kann.

Suwarto
quelle
0

Eine andere Möglichkeit, das gesamte Skript zu beenden, besteht darin, den slBefehl im Hintergrund auszuführen und dann das Signal abzufangen INT, um die gesamte Prozessgruppe des Skripts mit signal zu beenden HUP.

#!/bin/bash

trap 'trap - INT; kill -s HUP -- -$$' INT
#trap 'trap - INT; kill -s HUP 0' INT

while :
do
   sl & wait
done
chanze
quelle
-1

Verwenden Sie set -e, um den Fehler zu beenden.

#!/bin/bash
set -e
while :
do
    sl
done
Guo Chun Mao
quelle
Das geht nicht slstirbt nicht mit ctrl + c.
Duncan X Simpson
-1
while [ true ] 
do

  #check if script is running
  ps | grep script_name.sh | grep -v grep >/dev/null 2>&1

  if [ "$!" != "0" ] ; then
    break
  else

    kill -9 ` ps -ef | grep script_name.sh | cut -d "a" -f 1` 
    echo "kill -9 `get script PID`"

  fi

done

das sollte helfen.

coder007
quelle
2
Warum wird Ihrer Meinung nach die PID des letzten Hintergrundbefehls jemals 0 sein?
Manatwork
-1

Das tödliche Ding ist schrecklich, weil man es jetzt nie tut, wenn das Skript zweimal ausgeführt werden muss. UND Ihr Beendigungscode ist falsch.

while [ something ]; do

 if [ somethingelse ]; then
   echo shut down script with exit code 0
   exit 0
 fi
done

echo something else not happend
exit 2 # Return val important for example for monitoring

Kein Arbeiten. Lösung = benutze Perl. während öffnet eigene Bash

rene
quelle