Beenden einer Endlosschleife

Ich habe einen Befehl, den ich bei jedem Beenden automatisch erneut ausführen möchte, also habe ich Folgendes ausgeführt:

while [ 1 ]; do COMMAND; done; 

, aber wenn ich die Schleife nicht mit Strg-c stoppen kann, wird nur COMMAND und nicht die gesamte Schleife.

Wie würde ich etwas Ähnliches erreichen, das ich jedoch stoppen kann, ohne das Terminal schließen zu müssen?

Kommentare

  • Wenn ich ‚ m in bash bin, benutze ich einfach Strg-Z, um den Job zu stoppen und dann „% 1 „, um es zu töten.
  • Warten Sie einfach … Linus wurde mit den Worten zitiert: „Wir alle wissen, dass Linux großartig ist … es macht Endlosschleifen in 5 Sekunden. ” – also wirklich … warten Sie noch ein paar Sekunden, es sollte abgeschlossen sein.
  • @PaulCager hat auch bei mir funktioniert! Warum funktioniert es dort, wo Strg-C funktioniert? nicht?
  • @cirosantilli es beendet den äußeren Job (die Bash “ wrapper „). In einigen Situationen wird beispielsweise ‚ den “ BEFEHL “ nicht sofort beendet Wenn Sie es als Hintergrund verwenden, kann es lebendig vorbeischleichen, selbst wenn der Elternteil von ‚ tot ist. Aber die Schleife ist tot und ‚ ist der wichtige Teil.

Antwort

Überprüfen Sie den Beendigungsstatus des Befehls. Wenn der Befehl durch ein Signal beendet wurde, lautet der Exit-Code 128 + die Signalnummer. Aus der GNU-Online-Dokumentation für Bash :

Für die Zwecke der Shell ein Befehl Das Beenden mit einem Exit-Status von Null ist erfolgreich. Ein Exit-Status ungleich Null zeigt einen Fehler an. Dieses scheinbar kontraintuitive Schema wird verwendet, sodass es einen genau definierten Weg gibt, um den Erfolg anzuzeigen, und eine Vielzahl von Möglichkeiten, um verschiedene Fehlermodi anzuzeigen. Wenn ein Befehl mit einem schwerwiegenden Signal endet, dessen Nummer N ist, verwendet Bash den Wert 128 + N als Beendigungsstatus.

POSIX gibt außerdem an, dass der Wert eines Befehls, der durch ein Signal beendet wird, größer als 128 ist, aber seinen genauen Wert nicht wie bei GNU anzugeben scheint:

Der Beendigungsstatus eines Befehls, der beendet wurde, weil er ein Signal empfangen hat, wird als größer als 128 gemeldet.

Wenn Sie beispielsweise einen Befehl mit Control-C unterbrechen, lautet der Exit-Code 130, da SIGINT auf Unix-Systemen Signal 2 ist. Also:

while [ 1 ]; do COMMAND; test $? -gt 128 && break; done 

Kommentare

  • Es sollte erwähnt werden, dass dies tatsächlich nicht garantiert ist. Viele Anwendungen tun dies nicht.
  • @Kyle Jones: Können Sie einen Link zu den POSIX / GNU-Dokumenten erstellen, in denen dies erwähnt wird?
  • @cirosantilli Fertig.
  • @ KyleJones danke! Funktioniert immer noch nicht für COMMAND = paplay alert.ogg, möglicherweise weil paplay das Signal verarbeitet?
  • @cirosantilli Ja, das ‚ ist der Grund. Wenn ein Prozess das Signal verarbeitet und beendet, unterscheidet sich ‚ von dem Prozess, der durch ein nicht behandeltes Signal beendet wird.

Antwort

Sie können Ihren Job anhalten und in den Hintergrund stellen, während er mit Strg + z ausgeführt wird. Dann Sie kann Ihren Job beenden mit:

$ kill %1 

Wobei [1] Ihre Jobnummer ist.

Kommentare

  • Siehe auch diese Antwort für Erklärungen und mehr.
  • Diese relativ aktuelle Antwort funktioniert einfach. Muss sein upvoted. +1
  • Sie haben mir sehr geholfen. Dies ist, wonach ich in dieser Frage gesucht habe 🙂

Antwort

Ich würde sagen, es ist am besten, Ihre Endlosschleife in ein Skript einzufügen und dort Signale zu verarbeiten. Hier ist ein grundlegender Ausgangspunkt. Ich bin sicher, Sie möchten es an Ihre Bedürfnisse anpassen. Das Skript verwendet trap, um ctrl c (oder SIGTERM) abzufangen. Beendet den Befehl (ich habe sleep hier als Test verwendet) und beendet ihn.

cleanup () { kill -s SIGTERM $! exit 0 } trap cleanup SIGINT SIGTERM while [ 1 ] do sleep 60 & wait $! done 

Kommentare

  • Nice. Hier ‚ habe ich diesen Tipp verwendet, um einen Netcat-Wrapper zum automatischen Neustart zu erstellen: trap "exit 0" SIGINT SIGTERM; while true; do netcat -l -p 3000; done
  • Wenn Sie diesen trap -Ansatz für dasselbe (bash) Skript mit der zu tötenden Endlosschleife hinzufügen, verwenden Sie $$ anstelle von $! (siehe hier )

Antwort

Ich halte im Allgemeinen nur Strg-C gedrückt. Früher oder später wird es zwischen “ s und beenden Sie damit die while -Schleife. Vielleicht gibt es einen besseren Weg.

Kommentare

  • Ich weiß nicht warum, aber es schlägt für bestimmte BEFEHLE wie paplay für eine 1s-Datei fehl .
  • Es hat bei mir funktioniert
  • Das ‚ ist die rohe Kraft aller Lösungen hier. : /

Antwort

Wenn Sie bash mit -e ausführen Es wird unter allen Fehlerbedingungen beendet:

#!/bin/bash -e false # returns 1 echo This won"t be printed 

Kommentare

  • Die erste Zeile hier ist bei weitem Die einfachste Lösung für ein triviales Skript, für das Sie ‚ nicht zu viel Zeit aufwenden möchten!

Antwort

Warum nicht einfach

while [ 1 ]; do COMMAND || break; done; 

oder bei Verwendung in einem Skript

#!/bin/bash while [ 1 ]; do # ctrl+c terminates COMMAND and exits the while loop # (assuming COMMAND responds to ctrl+c) COMMAND || break done; 

Kommentare

  • Sehr elegante Lösung. Aber würde dies nicht ‚ nicht nur funktionieren, wenn COMMAND immer einen erfolgreichen Exit-Status zurückgibt?
  • Ja @howardh, dass ‚ ist richtig.

Antwort

  1. Dort können Sie einen Prozess jederzeit mit seiner PID beenden. “ s Sie müssen Ihr Terminal nicht schließen.
  2. Wenn Sie etwas in einer Endlosschleife wie einen Daemon ausführen möchten, sollten Sie es am besten in den Hintergrund stellen.
  3. while : erstellt eine Endlosschleife und erspart Ihnen das Schreiben der [ 1 ]

    while :; do COMMAND; done & 

Hiermit wird die PID gedruckt. Wenn Sie Ihre Eingabeaufforderung mit ctrl+d beenden, wird der Hintergrundjob nicht beendet, und Sie können den Job später mit kill PID

Wenn Sie den Überblick über Ihre PID verlieren, können Sie pstree -pa $USER oder pgrep -fl ".*PROCESS.*" verwenden, um sie zu finden

Antwort

Ich bevorzuge eine andere Lösung:

touch .runcmd; while [ -f ".runcmd" ]; do COMMAND; sleep 1; done 

In der richtigen Reihenfolge Um die Schleife zu beenden, gehen Sie einfach wie folgt vor:

rm .runcmd && kill `pidof COMMAND` 

Antwort

Was funktioniert vernünftig? gut für mich ist:

 while sleep 1; do COMMAND; done  

Dies funktioniert, weil Schlaf 1 für a bleibt während und wenn es Strg + c bekommt, kehrt es mit ungleich Null zurück und die Schleife wird beendet.

Kommentare

  • +1, Schlafzeit kann auch sein reduziert auf 0.5 oder 0.1: while sleep 0.1; do COMMAND; done

Antwort

Verwenden Sie trap

 exit_() { exit } while true do echo "running.." trap exit_ int done  

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.