Een oneindige lus beëindigen

Ik heb een commando dat ik elke keer dat het eindigt automatisch opnieuw wil laten uitvoeren, dus ik heb zoiets als dit uitgevoerd:

while [ 1 ]; do COMMAND; done; 

maar als ik de lus niet kan “stoppen met Ctrl-c , want dat doodt gewoon COMMAND en niet de hele lus.

Hoe zou ik iets soortgelijks bereiken, maar dat kan ik stoppen zonder de terminal te hoeven sluiten?

Reacties

  • Als ik ‘ m in bash gebruik, gebruik ik Ctrl-Z om de taak te stoppen en ” kill% 1 ” om het te doden.
  • Wacht maar … Linus werd als volgt geciteerd: “We weten allemaal dat Linux geweldig is … het doet oneindige loops in 5 seconden. ” – dus echt … wacht nog een paar seconden, het zou moeten zijn voltooid.
  • @PaulCager werkte ook voor mij! Waarom werkt het waar Ctrl-C doet niet?
  • @cirosantilli het doodt de buitenste baan (de bash ” wrapper “). In sommige situaties wint het ‘ om bijvoorbeeld de ” COMMAND ” onmiddellijk te doden , als je het op de achtergrond doet, kan het levend voorbij sluipen, zelfs als de ouder van ‘ dood is. Maar de lus is dood, en dat ‘ is het belangrijkste deel.

Antwoord

Controleer de exit-status van de opdracht. Als de opdracht werd beëindigd door een signaal, is de exitcode 128 + het signaalnummer. Van de GNU online documentatie voor bash :

Voor de doeleinden van de shell, een commando die afsluit met een nul-exitstatus is geslaagd. Een exitstatus anders dan nul duidt op een storing. Dit schijnbaar contra-intuïtieve schema wordt gebruikt, dus er is één goed gedefinieerde manier om succes aan te geven en een verscheidenheid aan manieren om verschillende faalwijzen aan te geven. Wanneer een commando eindigt op een fataal signaal waarvan het nummer N is, gebruikt Bash de waarde 128 + N als de exitstatus.

POSIX specificeert ook dat de waarde van een commando dat wordt beëindigd door een signaal groter is dan 128, maar lijkt niet de exacte waarde te specificeren zoals GNU doet:

De exitstatus van een commando dat is beëindigd omdat het een signaal heeft ontvangen, wordt gerapporteerd als groter dan 128.

Als u bijvoorbeeld een commando onderbreekt met control-C, wordt de exitcode 130, omdat SIGINT signaal 2 is op Unix-systemen. Dus:

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

Reacties

  • Er moet worden vermeld dat dit in feite niet gegarandeerd is veel applicaties zullen dit niet doen.
  • @Kyle Jones: kun je linken naar de POSIX / GNU-documenten die dat vermelden?
  • @cirosantilli Klaar.
  • @ KyleJones bedankt! Werkt het in de praktijk nog steeds niet voor COMMAND = paplay alert.ogg, misschien omdat paplay het signaal afhandelt?
  • @cirosantilli Ja, dat ‘ is de reden. Als een proces het signaal afhandelt en stopt, is dat ‘ anders dan het proces dat wordt beëindigd door een onverwerkt signaal.

Antwoord

U kunt stoppen en uw taak op de achtergrond plaatsen terwijl deze wordt uitgevoerd met ctrl + z . kan uw baan doden met:

$ kill %1 

Waar [1] uw baannummer is.

Opmerkingen

  • Zie ook dit antwoord voor uitleg en meer.
  • Dit relatief recente antwoord werkt gewoon. Moet worden upvoted. +1
  • Je hebt me veel geholpen. Dit is waar ik naar heb gezocht in deze vraag 🙂

Antwoord

Ik zou zeggen dat het misschien het beste is om je oneindige lus in een script te plaatsen en daar signalen af te handelen. Hier “een basisuitgangspunt . Ik weet zeker dat je het naar wens wilt aanpassen. Het script gebruikt trap om ctrl c (of SIGTERM) te vangen, doodt het commando (ik “ve gebruikt sleep hier als een test) en sluit af.

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

Reacties

  • Leuk. Hier ‘ zie je hoe ik deze tip heb gebruikt om een automatisch herstartende netcat-wrapper te maken: trap "exit 0" SIGINT SIGTERM; while true; do netcat -l -p 3000; done
  • als je deze trap benadering toevoegt aan hetzelfde (bash) script met de oneindige lus om te stoppen, gebruik dan $$ in plaats van $! (bekijk hier )

Answer

Over het algemeen houd ik Ctrl-C ingedrukt. Vroeg of laat zal het “registreren tussen COMMAND” s en beëindig daarmee de while lus. Misschien is er een betere manier.

Reacties

  • Weet niet waarom, maar het mislukt voor bepaalde COMMANDs zoals paplay op een 1s-bestand .
  • Het werkte voor mij
  • Dat ‘ de brute kracht is van alle oplossingen hier. : /

Answer

Als je bash uitvoert met -e het wordt afgesloten bij elke foutconditie:

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

Reacties

  • De eerste regel hier is verreweg de eenvoudigste oplossing voor een triviaal script waar je niet ‘ niet te veel tijd aan wilt besteden!

Antwoord

Waarom niet gewoon,

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

Of wanneer gebruikt in een script,

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

Reacties

  • Zeer elegante oplossing. Maar zou dit niet ‘ werken als COMMAND altijd een exit-status voor succes retourneert?
  • Ja @howardh, dat ‘ is correct.

Antwoord

  1. Je kunt een proces altijd afbreken met zijn PID, daar ” Het is niet nodig om je terminal te sluiten.
  2. Als je iets in een oneindige lus wilt draaien zoals een daemon, dan kun je het het beste op de achtergrond plaatsen
  3. while : zal een oneindige lus creëren en bespaart u het schrijven van de [ 1 ]

    while :; do COMMAND; done & 

Hiermee wordt de PID afgedrukt. Als u de prompt verlaat met ctrl+d, wordt de taak op de achtergrond “niet gestopt en kunt u de taak later overal beëindigen met kill PID

Als u uw PID uit het oog verliest, kunt u pstree -pa $USER of pgrep -fl ".*PROCESS.*" gebruiken om u te helpen deze te vinden

Antwoord

Ik geef de voorkeur aan een andere oplossing:

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

Om om de lus te stoppen, doe je gewoon:

rm .runcmd && kill `pidof COMMAND` 

Antwoord

Wat werkt redelijk goed voor mij is:

 while sleep 1; do COMMAND; done  

Dit werkt omdat slaap 1 lang blijft hangen while en als het ctrl + c krijgt, wordt het teruggegeven met een andere waarde dan nul en zal de lus eindigen.

Comments

  • +1, slaaptijd kan ook zijn gereduceerd tot 0.5 of 0.1: while sleep 0.1; do COMMAND; done

Antwoord

Gebruik trap

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

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *