Kończenie nieskończonej pętli

Mam polecenie, które chcę uruchamiać ponownie automatycznie za każdym razem, gdy się kończy, więc uruchomiłem coś takiego:

while [ 1 ]; do COMMAND; done; 

ale jeśli nie mogę „zatrzymać pętli za pomocą Ctrl-c , ponieważ to po prostu zabija COMMAND a nie całą pętlę.

Jak osiągnąć coś podobnego, ale co mogę zatrzymać bez konieczności zamykania terminala?

Komentarze

  • Jeśli ' m in bash, po prostu używam Ctrl-Z, aby zatrzymać zadanie, a następnie ” zabijam% 1 „, aby go zabić.
  • Poczekaj … Linus został zacytowany jako powiedział: „Wszyscy wiemy, że Linux jest świetny … robi nieskończone pętle w 5 sekund. ” – tak naprawdę … poczekaj jeszcze kilka sekund, powinno się zakończyć.
  • @PaulCager też zadziałało! Dlaczego działa tam, gdzie Ctrl-C robi nie?
  • @cirosantilli zabija zewnętrzną pracę (bash ” wrapper „). W niektórych sytuacjach wygrał na przykład ' t natychmiastowo zabił ” COMMAND ” , jeśli umieścisz go w tle, może przemknąć obok żywego, nawet jeśli rodzic ' nie żyje. Ale pętla jest martwa i to ' jest ważną częścią.

Odpowiedź

Sprawdź status zakończenia polecenia. Jeśli polecenie zostało zakończone sygnałem, kod wyjścia będzie wynosił 128 + numer sygnału. Z dokumentacji online GNU dla bash :

Do celów powłoki polecenie która kończy się z zerowym kodem zakończenia, powiodła się. Niezerowy status wyjścia oznacza błąd. Ten pozornie sprzeczny z intuicją schemat jest używany, więc istnieje jeden dobrze zdefiniowany sposób wskazywania sukcesu i wiele sposobów wskazywania różnych trybów awarii. Kiedy polecenie kończy się krytycznym sygnałem o numerze N, Bash używa wartości 128 + N jako kodu wyjścia.

POSIX określa również , że wartość polecenia zakończonego sygnałem jest większa niż 128, ale nie wydaje się określać jego dokładnej wartości, tak jak robi to GNU:

Status wyjścia polecenia, które zostało zakończone z powodu odebrania sygnału, będzie zgłoszony jako większy niż 128.

Na przykład, jeśli przerwiesz polecenie za pomocą control-C, kod wyjścia będzie wynosił 130, ponieważ SIGINT jest sygnałem 2 w systemach Unix. A więc:

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

Komentarze

  • Należy wspomnieć, że w rzeczywistości nie jest to gwarantowane wiele aplikacji tego nie zrobi.
  • @Kyle Jones: czy możesz zamieścić odnośniki do dokumentów POSIX / GNU, które o tym wspominają?
  • @cirosantilli Gotowe.
  • @ KyleJones dzięki! W praktyce nadal nie działa dla COMMAND = paplay alert.ogg, być może dlatego, że paplay obsługuje sygnał?
  • @cirosantilli Tak, to ' jest powodem. Jeśli proces obsługuje sygnał i kończy pracę, oznacza to, że ' jest inny niż proces kończony przez nieobsługiwany sygnał.

Odpowiedź

Możesz zatrzymać pracę i umieścić ją w tle podczas jej działania, używając ctrl + z . Następnie możesz możesz zabić swoją pracę:

$ kill %1 

Gdzie [1] to Twój numer pracy.

Komentarze

  • Zobacz także tę odpowiedź , aby uzyskać wyjaśnienia i nie tylko.
  • Ta stosunkowo nowa odpowiedź po prostu działa. Musi być głosowano. +1
  • Bardzo mi pomogłeś. Właśnie tego szukałem w tym pytaniu 🙂

Odpowiedź

Powiedziałbym, że najlepiej byłoby umieścić nieskończoną pętlę w skrypcie i tam obsługiwać sygnały. Oto podstawowy punkt wyjścia . Jestem pewien, że zechcesz go zmodyfikować, aby pasował. Skrypt używa trap do przechwytywania ctrl c (lub SIGTERM), wyłącza polecenie (użyłem tutaj sleep w ramach testu) i kończy pracę.

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

Komentarze

  • Świetnie. Oto ' jak wykorzystałem tę wskazówkę, aby utworzyć opakowanie netcat z automatycznym uruchomieniem: trap "exit 0" SIGINT SIGTERM; while true; do netcat -l -p 3000; done
  • jeśli dodasz to trap podejście do tego samego skryptu (bash) z nieskończoną pętlą do zabicia, użyj $$ zamiast $! (patrz tutaj )

Odpowiedź

Generalnie po prostu przytrzymuję klawisz Ctrl-C . Wcześniej czy później „zarejestruję się między COMMAND” s iw ten sposób zakończ pętlę while. Może jest lepszy sposób.

Komentarze

  • Nie wiem dlaczego, ale nie udaje się to w przypadku niektórych POLECEŃ, takich jak paplay w pliku 1s .
  • U mnie zadziałało
  • To ' jest brutalną siłą wszystkich rozwiązań tutaj. : /

Odpowiedź

Jeśli uruchomisz bash z -e zakończy działanie w przypadku każdego błędu:

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

Komentarze

  • Pierwsza linia jest zdecydowanie najprostsze rozwiązanie dla trywialnego skryptu, nad którym ' nie chcesz spędzać zbyt dużo czasu!

Odpowiedź

Dlaczego nie po prostu

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

Lub w przypadku użycia w skrypcie

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

Komentarze

  • Bardzo eleganckie rozwiązanie. Ale czy ' t nie zadziała tylko wtedy, gdy COMMAND zawsze zwraca status wyjścia sukcesu?
  • Tak @howardh, że ' jest poprawne.

Odpowiedź

  1. Zawsze możesz zabić proces używając jego PID, tam ” Nie ma potrzeby zamykania terminala
  2. Jeśli chcesz uruchomić coś w nieskończonej pętli, jak demon, najlepiej umieścić to w tle
  3. while : utworzy nieskończoną pętlę i zaoszczędzi ci pisania [ 1 ]

    while :; do COMMAND; done & 

Spowoduje to wydrukowanie PID. Jeśli wyjdziesz z monitu za pomocą ctrl+d, wtedy zadanie w tle nie zostanie zakończone i możesz później zabić je z dowolnego miejsca za pomocą kill PID

Jeśli zgubisz swój PID, możesz użyć pstree -pa $USER lub pgrep -fl ".*PROCESS.*", które pomogą Ci go znaleźć

Odpowiedź

Wolę inne rozwiązanie:

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

Aby aby zakończyć pętlę, po prostu zrób:

rm .runcmd && kill `pidof COMMAND` 

Odpowiedź

Co działa rozsądnie dobrze dla mnie jest:

 while sleep 1; do COMMAND; done  

To działa, ponieważ sen 1 trzyma się while i jeśli otrzyma ctrl + c, zwróci wartość niezerową, a pętla się zakończy.

Komentarze

  • +1, czas uśpienia również może być zredukowana do 0.5 lub 0.1: while sleep 0.1; do COMMAND; done

Odpowiedź

Użyj trap

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

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *