Terminando um loop infinito

41

Eu tenho um comando que desejo executar novamente automaticamente cada vez que ele termina, então eu corri algo assim:

while [ 1 ]; do COMMAND; done;

mas se eu não puder parar o loop com Ctrl-c , isso apenas mata COMMAND e não o loop inteiro.

Como eu conseguiria algo semelhante, mas que posso parar sem precisar fechar o terminal?

    
por howardh 04.07.2012 / 02:32

8 respostas

31

Verifique o status de saída do comando. Se o comando foi terminado por um sinal, o código de saída será 128 + o número do sinal. Da documentação on-line do GNU para o bash :

For the shell’s purposes, a command which exits with a zero exit status has succeeded. A non-zero exit status indicates failure. This seemingly counter-intuitive scheme is used so there is one well-defined way to indicate success and a variety of ways to indicate various failure modes. When a command terminates on a fatal signal whose number is N, Bash uses the value 128+N as the exit status.

POSIX também especifica que o valor de um comando que é terminado por um sinal é maior que 128, mas não parece especificar seu valor exato como o GNU:

The exit status of a command that terminated because it received a signal shall be reported as greater than 128.

Por exemplo, se você interromper um comando com o controle-C, o código de saída será 130, porque o SIGINT é o sinal 2 nos sistemas Unix. Então:

while [ 1 ]; do COMMAND; test $? -gt 128 && break; done
    
por 04.07.2012 / 03:04
35

Você pode parar e colocar seu trabalho em segundo plano enquanto estiver sendo executado usando ctrl + z . Então você pode matar seu trabalho com:

$ kill %1

Onde [1] é o seu número de trabalho.

    
por 25.03.2014 / 17:43
17

Eu diria que talvez seja melhor colocar seu loop infinito em um script e lidar com os sinais lá. Aqui está um ponto de partida básico . Tenho certeza que você vai querer modificá-lo para se adequar. O script usa trap para capturar ctrl - c (ou SIGTERM ), mata o comando (usei sleep aqui como teste) e sai.

cleanup ()
{
kill -s SIGTERM $!
exit 0
}

trap cleanup SIGINT SIGTERM

while [ 1 ]
do
    sleep 60 &
    wait $!
done
    
por 04.07.2012 / 06:14
16

Eu geralmente apenas pressiono Ctrl-C . Mais cedo ou mais tarde, ele será registrado entre COMMAND e, portanto, terminará o loop while . Talvez haja um jeito melhor.

    
por 04.07.2012 / 05:20
8

Se você executar o bash com -e , ele sairá em qualquer condição de erro:

#!/bin/bash -e
false # returns 1
echo This won't be printed
    
por 04.07.2012 / 07:00
4

Por que não simplesmente,

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

Ou quando usado em um script,

#!/bin/bash
while [ 1 ]; do
  # ctrl+c terminates COMMAND and exits the while loop
  # (assuming COMMAND responds to ctrl+c)
  COMMAND || break
done;
    
por 02.12.2015 / 19:06
2
  1. Você sempre pode matar um processo usando seu PID, não há necessidade de fechar seu terminal
  2. Se você deseja executar algo em um loop infinito como um daemon, é melhor colocá-lo em segundo plano
  3. while : criará um loop infinito e poupará você de escrever o [ 1 ]

    while :; do COMMAND; done &
    

Isto imprimirá o PID. Se você sair do prompt usando ctrl+d , o trabalho em segundo plano não será encerrado e, mais tarde, você poderá eliminar o trabalho de qualquer lugar usando kill PID

Se você perder o controle do seu PID, use pstree -pa $USER ou pgrep -fl '.*PROCESS.*' para encontrá-lo

    
por 24.10.2013 / 06:55
2

Eu prefiro outra solução:

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

Para matar o loop, faça:

rm .runcmd && kill 'pidof COMMAND'
    
por 06.04.2018 / 21:00

Tags