Avsluta en oändlig slinga

Jag har ett kommando som jag vill ha kört igen automatiskt varje gång det avslutas, så jag körde något så här:

while [ 1 ]; do COMMAND; done; 

men om jag inte kan stoppa slingan med Ctrl-c eftersom det bara dödar COMMAND och inte hela slingan.

Hur skulle jag uppnå något liknande men som jag kan stoppa utan att behöva stänga terminalen?

Kommentarer

  • Om jag ’ m i bash använder jag bara Ctrl-Z för att stoppa jobbet och sedan ” dödar% 1 ” för att döda det.
  • Vänta bara … Linus citerades för att säga: ”Vi vet alla att Linux är jättebra … det gör oändliga slingor på fem sekunder. ” – så verkligen … vänta bara några sekunder till, det ska slutföras.
  • @PaulCager fungerade också för mig! Varför fungerar det där Ctrl-C gör inte?
  • @cirosantilli det dödar det yttre jobbet (bash ” omslag ”). I vissa situationer kommer det ’ inte att döda ” COMMAND ”, till exempel , om du bakgrundsbild kan den smyga sig levande även om den ’ s förälder är död. Men slingan är död och att ’ är den viktiga delen.

Svar

Kontrollera kommandot utgångsstatus. Om kommandot avslutades med en signal kommer utgångskoden att vara 128 + signalnumret. Från GNU online-dokumentation för bash :

För skalets ändamål, ett kommando som går ut med nollutgångsstatus har lyckats. En utgångsstatus som inte är noll indikerar fel. Detta till synes kontraintuitiva schema används så det finns ett väldefinierat sätt att indikera framgång och en mängd olika sätt att indikera olika misslyckanden. När ett kommando slutar på en dödlig signal vars nummer är N, använder Bash värdet 128 + N som utgångsstatus.

POSIX anger också att värdet på ett kommando som avslutas av en signal är större än 128, men det verkar inte som om det anger exakt värde som GNU gör:

Utgångsstatus för ett kommando som avslutades på grund av att det mottog en signal ska rapporteras som större än 128.

Till exempel om du avbryter ett kommando med kontroll-C kommer utgångskoden att vara 130, eftersom SIGINT är signal 2 på Unix-system. Så:

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

Kommentarer

  • Det bör nämnas att detta faktiskt inte är garanterat många applikationer kommer inte att göra detta.
  • @Kyle Jones: kan du länka till POSIX / GNU-dokument som nämner det?
  • @cirosantilli Klar.
  • @ KyleJones tack! Fungerar du fortfarande inte i COMMAND = paplay alert.ogg, kanske för att paplay hanterar signalen?
  • @cirosantilli Ja, att ’ är anledningen. Om en process hanterar signalen och avslutar är den ’ annorlunda än processen som avslutas av en obehandlad signal.

Svar

Du kan stoppa och lägga ditt jobb i bakgrunden medan det körs med ctrl + z . Då kan döda ditt jobb med:

$ kill %1 

Var [1] är ditt jobbnummer.

Kommentarer

  • Se även det här svaret för förklaringar och mer.
  • Det relativt nya svaret fungerar helt enkelt. Behöver vara uppröstad. +1
  • Du hjälpte mig mycket. Det här har jag letat efter i den här frågan 🙂

Svar

Jag skulle säga att det kan vara bäst att sätta din oändliga slinga i ett skript och hantera signaler där. Här ”är grundläggande startpunkt . Jag är säker på att du vill ändra den så att den passar. Skriptet använder trap för att fånga ctrl c (eller SIGTERM), dödar kommandot (jag har använt sleep här som ett test) och avslutar.

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

Kommentarer

  • Trevligt. Här ’ hur jag använde det här tipset för att skapa ett autostart om netcat-omslag: trap "exit 0" SIGINT SIGTERM; while true; do netcat -l -p 3000; done
  • om du lägger till detta trap tillvägagångssätt till samma (bash) skript med den oändliga slingan som ska dödas, använd $$ istället för $! (se här )

Svar

Jag håller i allmänhet bara ned Ctrl-C . Förr eller senare kommer det ”att registrera mellan COMMAND” s och därmed avsluta while -slingan. Kanske finns det ett bättre sätt.

Kommentarer

  • Inte säker på varför, men det misslyckas för vissa COMMANDs som paplay på en 1s-fil .
  • Det fungerade för mig
  • Att ’ är allvarliga kraften för alla lösningar här. : /

Svar

Om du kör bash med -e den kommer att avslutas under alla felvillkor:

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

Kommentarer

  • Den första raden här är överlägset den enklaste lösningen för ett trivialt skript som du inte ’ inte vill spendera för mycket tid på!

Svar

Varför inte helt enkelt,

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

Eller när det används i ett skript,

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

Kommentarer

  • Mycket elegant lösning. Men skulle ’ inte detta bara fungera om COMMAND alltid returnerar en framgångsutgångsstatus?
  • Ja @howardh, att ’ är korrekt.

Svar

  1. Du kan alltid döda en process med dess PID, där ” s inget behov av att stänga din terminal
  2. Om du vill köra något i en oändlig slinga som en demon så skulle du bäst lägga det i bakgrunden
  3. while : skapar en oändlig slinga och sparar dig när du skriver [ 1 ]

    while :; do COMMAND; done & 

Detta skriver ut PID. Om du avslutar din uppmaning med ctrl+d kommer bakgrundsjobbet inte att avslutas och du kan senare döda jobbet var som helst med kill PID

Om du tappar koll på din PID kan du använda pstree -pa $USER eller pgrep -fl ".*PROCESS.*" för att hjälpa dig hitta den

Svar

Jag föredrar en annan lösning:

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

I ordning för att döda slingan, gör bara:

rm .runcmd && kill `pidof COMMAND` 

Svar

Vad fungerar rimligt bra för mig är:

 while sleep 1; do COMMAND; done  

Detta fungerar eftersom sömn 1 stannar kvar i en medan och om det blir ctrl + c kommer det tillbaka utan noll och slingan avslutas.

Kommentarer

  • +1, sömntiden kan också vara reducerad till 0.5 eller 0.1: while sleep 0.1; do COMMAND; done

Svar

Använd trap

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

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *