Terminare un ciclo infinito

Ho un comando che voglio che venga eseguito di nuovo automaticamente ogni volta che termina, quindi ho eseguito qualcosa del genere:

while [ 1 ]; do COMMAND; done; 

ma se non riesco a “t interrompere il ciclo con Ctrl-c in quanto ciò uccide COMMAND e non lintero ciclo.

Come potrei ottenere qualcosa di simile ma che posso fermare senza dover chiudere il terminale?

Commenti

  • Se ‘ m in bash, uso semplicemente Ctrl-Z per interrompere il lavoro e poi ” uccido% 1 ” per ucciderlo.
  • Aspetta … Linus è stato citato come dicendo: “Sappiamo tutti che Linux è fantastico … fa loop infiniti in 5 secondi. “ – quindi davvero … aspetta ancora qualche secondo, dovrebbe essere completato.
  • @PaulCager ha funzionato anche per me! Perché funziona dove Ctrl-C fa no?
  • @cirosantilli uccide il lavoro esterno (il bash ” wrapper “). In alcune situazioni, ‘ non interrompe immediatamente il ” COMANDO “, ad esempio , se lo metti in background, potrebbe sfuggire di nascosto anche se il genitore di ‘ è morto. Ma il ciclo è morto e quella ‘ è la parte importante.

Risposta

Controlla lo stato di uscita del comando. Se il comando è stato terminato da un segnale, il codice di uscita sarà 128 + il numero del segnale. Dalla documentazione in linea GNU per bash :

Per gli scopi della shell, un comando che esce con uno stato di uscita zero è riuscito. Uno stato di uscita diverso da zero indica un errore. Questo schema apparentemente controintuitivo viene utilizzato quindi cè un modo ben definito per indicare il successo e una varietà di modi per indicare varie modalità di fallimento. Quando un comando termina con un segnale fatale il cui numero è N, Bash utilizza il valore 128 + N come stato di uscita.

POSIX specifica anche che il valore di un comando terminato da un segnale è maggiore di 128, ma non sembra specificare il suo valore esatto come fa GNU:

Lo stato di uscita di un comando terminato perché ha ricevuto un segnale deve essere segnalato come maggiore di 128.

Ad esempio, se interrompi un comando con control-C il codice di uscita sarà 130, perché SIGINT è il segnale 2 sui sistemi Unix. Quindi:

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

Commenti

  • Va detto che questo non è garantito, infatti, molte applicazioni non lo faranno.
  • @Kyle Jones: puoi collegarti ai documenti POSIX / GNU che lo menzionano?
  • @cirosantilli Fatto.
  • @ KyleJones grazie! Ancora in pratica non funziona per COMMAND = paplay alert.ogg, forse perché paplay gestisce il segnale?
  • @cirosantilli Sì, questo è il motivo ‘. Se un processo gestisce il segnale e si chiude, ‘ è diverso dal processo terminato da un segnale non gestito.

Risposta

Puoi interrompere e mettere il tuo lavoro in background mentre è in esecuzione usando ctrl + z . Quindi può uccidere il tuo lavoro con:

$ kill %1 

dove [1] è il numero del tuo lavoro.

Commenti

  • Vedi anche questa risposta per spiegazioni e altro.
  • Questa risposta relativamente recente funziona semplicemente. Deve essere voto positivo. +1
  • Mi hai aiutato molto. Questo è ciò che ho cercato in questa domanda 🙂

Risposta

Direi che potrebbe essere meglio inserire il tuo ciclo infinito in uno script e gestire i segnali lì. Ecco “un punto di partenza di base . Sono sicuro che vorrai modificarlo per adattarlo. Lo script utilizza trap per catturare ctrl c (o SIGTERM), interrompe il comando (ho usato sleep qui come test) ed esce.

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

Commenti

  • Bello. Ecco ‘ come ho utilizzato questo suggerimento per creare un wrapper netcat con riavvio automatico: trap "exit 0" SIGINT SIGTERM; while true; do netcat -l -p 3000; done
  • se aggiungi questo approccio trap allo stesso script (bash) con il ciclo infinito da eliminare, utilizza $$ invece di $! (vedi qui )

Risposta

In genere tengo premuto Ctrl-C . Prima o poi verrà registrato tra COMMAND” e quindi terminare il ciclo while. Forse esiste un modo migliore.

Commenti

  • Non sono sicuro del perché, ma fallisce per alcuni COMANDI come paplay su un file 1s .
  • Ha funzionato per me
  • Quella ‘ è la forza bruta di tutte le soluzioni qui. : /

Risposta

Se esegui bash con -e uscirà in qualsiasi condizione di errore:

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

Commenti

  • La prima riga qui è di gran lunga la soluzione più semplice per uno script banale su cui non ‘ vorresti dedicare troppo tempo!

Rispondi

Perché non semplicemente,

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

Oppure, se utilizzato in uno script,

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

Commenti

  • Soluzione molto elegante. Ma ‘ funzionerebbe solo se COMMAND restituisce sempre uno stato di uscita riuscito?
  • Sì @howardh, che ‘ è corretto.

Rispondi

  1. Puoi sempre terminare un processo usando il suo PID, lì ” Non è necessario chiudere il terminale
  2. Se vuoi eseguire qualcosa in un ciclo infinito come un demone, allora è meglio metterlo in background
  3. while : creerà un ciclo infinito e ti eviterà di scrivere [ 1 ]

    while :; do COMMAND; done & 

Questo stamperà il PID. Se esci dal prompt utilizzando ctrl+d, il lavoro in background non si “interrompe e in seguito puoi terminare il lavoro da qualsiasi luogo utilizzando kill PID

Se perdi traccia del tuo PID, puoi utilizzare pstree -pa $USER o pgrep -fl ".*PROCESS.*" per trovarlo

Risposta

Preferisco unaltra soluzione:

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

In ordine per terminare il ciclo, basta fare:

rm .runcmd && kill `pidof COMMAND` 

Answer

Cosa funziona ragionevolmente bene per me è:

 while sleep 1; do COMMAND; done  

Funziona perché sleep 1 rimane in giro per un mentre e se ottiene ctrl + c ritorna con diverso da zero e il ciclo terminerà.

Commenti

  • +1, anche il tempo di sospensione può essere ridotto a 0.5 o 0.1: while sleep 0.1; do COMMAND; done

Risposta

Utilizza trap

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

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *