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 attpaplay
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
- Du kan alltid döda en process med dess PID, där ” s inget behov av att stänga din terminal
- 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
-
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
eller0.1
:while sleep 0.1; do COMMAND; done
Svar
Använd trap
–
exit_() { exit } while true do echo "running.." trap exit_ int done