Afslutning af en uendelig sløjfe

Jeg har en kommando, som jeg gerne vil have kørt igen automatisk hver gang den afsluttes, så jeg kørte noget som dette:

while [ 1 ]; do COMMAND; done; 

men hvis jeg ikke kan stoppe sløjfen med Ctrl-c da det bare dræber COMMAND og ikke hele sløjfen.

Hvordan ville jeg opnå noget lignende, men som jeg kan stoppe uden at skulle lukke terminalen?

Kommentarer

  • Hvis jeg ‘ m i bash bruger jeg bare Ctrl-Z til at stoppe jobbet og derefter ” dræbe% 1 ” for at dræbe det.
  • Bare vent … Linus blev citeret for at sige: “Vi ved alle, at Linux er fantastisk … det gør uendelige sløjfer om 5 sekunder. ” – så virkelig … bare vent et par sekunder mere, det skal fuldføres.
  • @PaulCager arbejdede også for mig! Hvorfor fungerer det, hvor Ctrl-C gør ikke?
  • @cirosantilli det dræber det ydre job (bash ” indpakning “). I nogle situationer vil det ‘ ikke dræbe straks ” COMMAND ” , hvis du baggrunde det, kan det snige sig levende, selvom det ‘ forælder er død. Men sløjfen er død, og at ‘ er den vigtige del.

Svar

Kontroller kommandens afslutningsstatus. Hvis kommandoen blev afsluttet med et signal, vil udgangskoden være 128 + signalnummeret. Fra GNU online dokumentation til bash :

Til shellens formål er en kommando der afslutter med nul udgangsstatus er lykkedes. En udgangsstatus, der ikke er nul, angiver fejl. Denne tilsyneladende kontraintuitive ordning bruges, så der er en veldefineret måde at indikere succes på og en række forskellige måder at indikere forskellige fiaskotilstande på. Når en kommando afsluttes på et fatalt signal, hvis nummer er N, bruger Bash værdien 128 + N som udgangsstatus.

POSIX specificerer også , at værdien af en kommando, der afsluttes af et signal, er større end 128, men synes ikke at angive den nøjagtige værdi som GNU gør:

Status for en kommando, der afsluttes, fordi den modtog et signal, skal rapporteres som større end 128.

For eksempel hvis du afbryder en kommando med kontrol-C, vil udgangskoden være 130, fordi SIGINT er signal 2 på Unix-systemer. Så:

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

Kommentarer

  • Det skal nævnes, at dette faktisk ikke er garanteret mange applikationer kan ikke gøre dette.
  • @Kyle Jones: kan du linke til POSIX / GNU-dokumenterne, der nævner det?
  • @cirosantilli Udført.
  • @ KyleJones tak! Arbejder du stadig ikke i COMMAND = paplay alert.ogg, måske fordi paplay håndterer signalet?
  • @cirosantilli Ja, at ‘ er årsagen. Hvis en proces håndterer signalet og afslutter, er ‘ anderledes end processen afsluttes med et ikke-håndteret signal.

Svar

Du kan stoppe og sætte dit job i baggrunden, mens det kører ved hjælp af ctrl + z . Så skal du kan dræbe dit job med:

$ kill %1 

Hvor [1] er dit jobnummer.

Kommentarer

  • Se også dette svar for forklaringer og mere.
  • Dette relativt nylige svar virker bare. Skal være opstemt. +1
  • Du hjalp mig meget. Dette er hvad jeg har søgt efter i dette spørgsmål 🙂

Svar

Jeg vil sige, at det måske er bedst at sætte din uendelige løkke i et script og håndtere signaler der. Her “er grundlæggende startpunkt . Jeg er sikker på, at du vil ændre det, så det passer. Scriptet bruger trap til at fange ctrl c (eller SIGTERM), dræber kommandoen (jeg har brugt sleep her som en test) og afslutter.

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

Kommentarer

  • Dejligt. Her ‘ hvordan jeg brugte dette tip til at lave en autorestarting netcat wrapper: trap "exit 0" SIGINT SIGTERM; while true; do netcat -l -p 3000; done
  • Hvis du tilføjer denne trap tilgang til det samme (bash) script med den uendelige løkke, der skal dræbes, skal du bruge $$ i stedet for $! (se her )

Svar

Jeg holder normalt bare Ctrl-C nede. Før eller senere registreres det mellem COMMAND” s og således afslut while loop. Måske er der en bedre måde.

Kommentarer

  • Ikke sikker på hvorfor, men det mislykkes for visse COMMANDs som paplay på en 1s-fil .
  • Det fungerede for mig
  • At ‘ er brute force for alle løsninger her. : /

Svar

Hvis du kører bash med -e det afsluttes under eventuelle fejltilstande:

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

Kommentarer

  • Den første linje her er langt den enkleste løsning til et trivielt script, som du ikke ‘ ikke vil bruge for meget tid på!

Svar

Hvorfor ikke bare,

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

Eller når det bruges i et script,

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

Kommentarer

  • Meget elegant løsning. Men ville ‘ ikke dette kun fungere, hvis COMMAND altid returnerer en succes exit status?
  • Ja @howardh, at ‘ er korrekt.

Svar

  1. Du kan altid dræbe en proces ved hjælp af dens PID, der ” er det ikke nødvendigt at lukke din terminal
  2. Hvis du vil køre noget i en uendelig løkke som en dæmon, skal du bedst sætte det i baggrunden
  3. while : opretter en uendelig løkke og sparer dig ved at skrive [ 1 ]

    while :; do COMMAND; done & 

Dette udskriver PID. Hvis du afslutter din prompt ved hjælp af ctrl+d, vil baggrundsjobbet ikke afslutte, og du kan senere dræbe jobbet hvor som helst ved hjælp af kill PID

Hvis du mister styr på din PID, kan du bruge pstree -pa $USER eller pgrep -fl ".*PROCESS.*" til at hjælpe dig med at finde den

Svar

Jeg foretrækker en anden løsning:

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

I rækkefølge for at dræbe sløjfen skal du bare gøre:

rm .runcmd && kill `pidof COMMAND` 

Svar

Hvad fungerer med rimelighed godt for mig er:

 while sleep 1; do COMMAND; done  

Dette fungerer, fordi sove 1 sidder fast i en mens og hvis det bliver ctrl + c, vender det tilbage med ikke nul, og sløjfen afsluttes.

Kommentarer

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

Svar

Brug trap

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

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *