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
- Puoi sempre terminare un processo usando il suo PID, lì ” Non è necessario chiudere il terminale
- Se vuoi eseguire qualcosa in un ciclo infinito come un demone, allora è meglio metterlo in background
-
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
o0.1
:while sleep 0.1; do COMMAND; done
Risposta
Utilizza trap
–
exit_() { exit } while true do echo "running.." trap exit_ int done