Encerrando um loop infinito

Tenho um comando que quero que seja executado automaticamente sempre que ele terminar, então executei algo assim:

while [ 1 ]; do COMMAND; done; 

mas se eu não conseguir parar o loop com Ctrl-c , pois isso simplesmente mata COMMAND e não o loop inteiro.

Como eu alcançaria algo semelhante, mas que posso parar sem ter que fechar o terminal?

Comentários

  • Se eu ‘ m no bash, apenas uso Ctrl-Z para interromper o trabalho e ” kill% 1 ” para matá-lo.
  • Espere … Linus foi citado como tendo dito: “Todos nós sabemos que o Linux é ótimo … ele faz loops infinitos em 5 segundos. ” – então, sério … espere mais alguns segundos, ele deve terminar.
  • @PaulCager funcionou para mim também! Por que funciona onde Ctrl-C funciona não?
  • @cirosantilli ele mata o trabalho externo (o bash ” wrapper “). Em algumas situações, ele conseguiu ‘ t matar imediatamente o ” COMANDO “, por exemplo , se você fizer isso em segundo plano, ele pode passar despercebido mesmo se ‘ seu pai estiver morto. Mas o loop está morto e essa ‘ é a parte importante.

Resposta

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

Para fins de shell, um comando que sai com um status de saída zero foi bem-sucedido. Um status de saída diferente de zero indica falha. Esse esquema aparentemente contra-intuitivo é usado para que haja uma maneira bem definida de indicar o sucesso e uma variedade de maneiras de indicar vários modos de falha. Quando um comando termina em um sinal fatal cujo número é N, o Bash usa o valor 128 + N como o status de saída.

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

O status de saída de um comando que terminou porque recebeu um sinal deve ser relatado como superior a 128.

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

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

Comentários

  • Deve ser mencionado que isso não é garantido, de fato, muitos aplicativos não farão isso.
  • @Kyle Jones: você pode criar um link para os documentos POSIX / GNU que mencionam isso?
  • @cirosantilli Concluído.
  • @ KyleJones, obrigado! Ainda na prática, não está funcionando para COMMAND = paplay alert.ogg, talvez porque paplay lida com o sinal?
  • @cirosantilli Sim, esse ‘ é o motivo. Se um processo lida com o sinal e sai, isso ‘ é diferente do processo sendo encerrado por um sinal não tratado.

Resposta

Você pode interromper e colocar seu trabalho em segundo plano enquanto ele está sendo executado usando ctrl + z . Então você pode eliminar seu trabalho com:

$ kill %1 

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

Comentários

  • Consulte também esta resposta para obter explicações e muito mais.
  • Esta resposta relativamente recente simplesmente funciona. Precisa ser voto positivo. +1
  • Você me ajudou muito. Isso é o que eu pesquisei nesta pergunta 🙂

Resposta

Eu diria que pode ser melhor colocar seu loop infinito em um script e manipular sinais lá. Aqui é 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 (eu usei sleep aqui como um teste) e sai.

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

Comentários

  • Legal. Aqui ‘ como usei esta dica para fazer um wrapper netcat de reinicialização automática: trap "exit 0" SIGINT SIGTERM; while true; do netcat -l -p 3000; done
  • se você adicionar esta abordagem trap ao mesmo script (bash) com o loop infinito a ser eliminado, use $$ em vez de $! (veja aqui )

Resposta

Geralmente, apenas mantenho pressionado Ctrl-C . Mais cedo ou mais tarde, ele “será registrado entre COMMAND” se encerrar o loop while. Talvez haja uma maneira melhor.

Comentários

  • Não sei por que, mas falha para certos COMANDOS como paplay em um arquivo 1s .
  • Funcionou para mim
  • Essa ‘ é a força bruta de todas as soluções aqui. : /

Resposta

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 

Comentários

  • A primeira linha aqui é de longe a solução mais simples para um script trivial no qual você não ‘ não deseja gastar muito tempo!

Resposta

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; 

Comentários

  • Solução muito elegante. Mas não ‘ isso só funcionaria se COMMAND sempre retornasse um status de saída de sucesso?
  • Sim @howardh, que ‘ está correto.

Resposta

  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 evitará que você escreva [ 1 ]

    while :; do COMMAND; done & 

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

Se você perder o controle do seu PID, poderá usar pstree -pa $USER ou pgrep -fl ".*PROCESS.*" para ajudá-lo a encontrá-lo

Resposta

Prefiro outra solução:

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

Em ordem para encerrar o loop, basta fazer:

rm .runcmd && kill `pidof COMMAND` 

Responder

O que funciona razoavelmente bom para mim é:

 while sleep 1; do COMMAND; done  

Isso funciona porque o sono 1 permanece por um enquanto e se ele obtiver ctrl + c, ele retorna com um valor diferente de zero e o loop será encerrado.

Comentários

  • +1, o tempo de sono também pode ser reduzido para 0.5 ou 0.1: while sleep 0.1; do COMMAND; done

Resposta

Use trap

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

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *