Avslutte en uendelig løkke

Jeg har en kommando som jeg vil ha kjørt igjen automatisk hver gang den avsluttes, så jeg kjørte noe sånt:

while [ 1 ]; do COMMAND; done; 

men hvis jeg ikke kan stoppe sløyfen med Ctrl-c da det bare dreper COMMAND og ikke hele sløyfen.

Hvordan ville jeg oppnå noe lignende, men som jeg kan stoppe uten å måtte stenge terminalen?

Kommentarer

  • Hvis jeg ‘ m i bash bruker jeg bare Ctrl-Z for å stoppe jobben og deretter » dreper% 1 » for å drepe det.
  • Bare vent … Linus ble sitert: “Vi vet alle at Linux er flott … det gjør uendelige løkker på 5 sekunder. ” – så egentlig … bare vent noen sekunder til, det skal fullføres.
  • @PaulCager jobbet også for meg! Hvorfor fungerer det der Ctrl-C gjør ikke?
  • @cirosantilli det dreper den ytre jobben (bash » wrapper «). I noen situasjoner vil den ikke ‘ t umiddelbart drepe » KOMMANDO » , hvis du bakgrunner den, kan den snike seg levende selv om den ‘ sin forelder er død. Men sløyfen er død, og at ‘ er den viktigste delen.

Svar

Kontroller avslutningsstatus for kommandoen. Hvis kommandoen ble avsluttet med et signal, vil utgangskoden være 128 + signalnummeret. Fra GNU online dokumentasjon for bash :

For skallets formål, en kommando som går ut med null utgangsstatus har lyktes. En utgangsstatus som ikke er null indikerer feil. Denne tilsynelatende kontraintuitive ordningen brukes, så det er en veldefinert måte å indikere suksess på og en rekke måter å indikere forskjellige feilmodus på. Når en kommando avsluttes på et dødelig signal med tallet N, bruker Bash verdien 128 + N som utgangsstatus.

POSIX spesifiserer også at verdien av en kommando som avsluttes av et signal er større enn 128, men ikke ser ut til å spesifisere den eksakte verdien som GNU gjør:

Utgangsstatus for en kommando som ble avsluttet fordi den mottok et signal, skal rapporteres som større enn 128.

Hvis du for eksempel avbryter en kommando med kontroll-C, vil utgangskoden være 130, fordi SIGINT er signal 2 på Unix-systemer. Så:

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

Kommentarer

  • Det skal nevnes at dette ikke er garantert, faktisk mange applikasjoner vil ikke gjøre dette.
  • @Kyle Jones: kan du lenke til POSIX / GNU-dokumentene som nevner det?
  • @cirosantilli Ferdig.
  • @ Takk, KyleJones! Jobber du fremdeles ikke for COMMAND = paplay alert.ogg, kanskje fordi paplay håndterer signalet?
  • @cirosantilli Ja, at ‘ er årsaken. Hvis en prosess håndterer signalet og avsluttes, er ‘ annerledes enn prosessen som avsluttes med et uhåndtert signal.

Svar

Du kan stoppe og sette jobben din i bakgrunnen mens den kjører med ctrl + z . Så du kan drepe jobben din med:

$ kill %1 

Hvor [1] er jobbnummeret ditt.

Kommentarer

  • Se også dette svaret for forklaringer og mer.
  • Dette relativt nylige svaret virker ganske enkelt. Må være oppstemt. +1
  • Du hjalp meg mye. Dette har jeg søkt etter i dette spørsmålet 🙂

Svar

Jeg vil si at det kan være best å sette den uendelige sløyfen din i et skript og håndtere signaler der. Her «er grunnleggende utgangspunkt . Jeg er sikker på at du vil endre den slik at den passer. Skriptet bruker trap for å fange ctrl c (eller SIGTERM), dreper kommandoen (jeg har brukt sleep her som en test) og avslutter.

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

Kommentarer

  • Hyggelig. Her ‘ hvordan jeg brukte dette tipset til å lage en autorestarting netcat wrapper: trap "exit 0" SIGINT SIGTERM; while true; do netcat -l -p 3000; done
  • hvis du legger til denne trap tilnærmingen til det samme (bash) skriptet med den uendelige sløyfen som skal drepes, bruk $$ i stedet for $! (se her )

Svar

Jeg holder vanligvis bare nede Ctrl-C . Før eller senere registreres det mellom COMMAND» s og dermed avslutte while sløyfen. Kanskje det er en bedre måte.

Kommentarer

  • Ikke sikker på hvorfor, men det mislykkes for visse KOMMANDOER som paplay på en 1s-fil .
  • Det fungerte for meg
  • At ‘ er den brute kraften til alle løsningene her. : /

Svar

Hvis du kjører bash med -e den vil gå ut under eventuelle feilforhold:

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

Kommentarer

  • Den første linjen her er langt den enkleste løsningen for et trivielt skript som du ikke ‘ ikke vil bruke for mye tid på!

Svar

Hvorfor ikke bare,

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

Eller når det brukes i et 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

  • Veldig elegant løsning. Men ville ikke ‘ ikke dette bare fungere hvis COMMAND alltid returnerer en vellykket exit-status?
  • Ja @howardh, at ‘ er riktig.

Svar

  1. Du kan alltid drepe en prosess ved hjelp av PID, der » det er ikke nødvendig å lukke terminalen din
  2. Hvis du vil kjøre noe i en uendelig løkke som en demon, bør du sette den i bakgrunnen
  3. while : oppretter en uendelig løkke og sparer deg når du skriver [ 1 ]

    while :; do COMMAND; done & 

Dette vil skrive ut PID. Hvis du avslutter meldingen din ved å bruke ctrl+d, vil ikke bakgrunnsjobben slutte, og du kan senere drepe jobben hvor som helst ved hjelp av kill PID

Hvis du mister oversikten over PID-en din, kan du bruke pstree -pa $USER eller pgrep -fl ".*PROCESS.*" for å hjelpe deg med å finne den

Svar

Jeg foretrekker en annen løsning:

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

I rekkefølge for å drepe løkken, gjør bare:

rm .runcmd && kill `pidof COMMAND` 

Svar

Hva fungerer rimelig vel for meg er:

 while sleep 1; do COMMAND; done  

Dette fungerer fordi søvn 1 holder seg i en mens og hvis det blir ctrl + c, returnerer det uten null og sløyfen avsluttes.

Kommentarer

  • +1, kan også søvntiden være redusert til 0.5 eller 0.1: while sleep 0.1; do COMMAND; done

Svar

Bruk trap

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

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *