Como fazer com que ctrl + c / not / interrompa o loop while?

11

Dado este loop:

while sleep 10s ; do
  something-that-runs-forever
done

Quando pressiono Ctrl + C, o loop while é interrompido. O que eu quero fazer é interromper o processo "algo", deixar 10 segundos passar e reiniciar "algo".

Como faço para que ctrl + c afete apenas "algo", e não o loop while?

EDIT: "interromper" como em SIGINT. Mate. Abortar. Terminar. Não "interromper" como em "pausar".

bos
fonte
Se você quiser apenas fazer uma pausa, por que não usar Ctrl + Z, aguarde 10 segundos e execute fg? Por que usar Ctrl + C?
terdon
@terdon: Obrigado pelo comentário, posso estar correndo com a resposta. Precisa ler mais sobre o requisito de OPs
Inian
@terdon: Não quero pausar. Quero 10 segundos para passar, como escrevi.
bos
Você disse: What I want to do is to interrupt the "something"-process, let 10 seconds pass, and then restart "something". Se você pressionar Ctrl + Z, aguarde 10s e depois execute fg, é exatamente o que acontecerá. Talvez você possa editar sua pergunta e dar um exemplo específico para que possamos entender melhor?
terdon
3
Eu pensei que, no contexto de Ctrl + C, a interrupção era inequívoca, mas obviamente eu estava errado. Eu editei agora.
bos

Respostas:

18

Deveria funcionar se você apenas trap SIGINTpara alguma coisa. Como :( true).

#!/bin/sh
trap ":" INT    
while sleep 10s ; do
    something-that-runs-forever
done

Interromper o something...comando não faz com que o shell saia agora, pois ignora o sinal. No entanto, se você ^ C o sleepprocesso, ele sairá com uma falha e o loop será interrompido devido a isso. Mova o sleeppara o interior do loop ou adicione algo parecido || truepara evitar isso.

Observe que, se você trap "" INTignora completamente o sinal (em vez de atribuir um comando a ele), ele também é ignorado no processo filho; portanto, você também não pode interromper something.... Isso é mencionado explicitamente no manual do Bash, pelo menos :

Se arg é a cadeia nula, o sinal especificado por cada sigspec é ignorado pelo shell e pelos comandos que ele chama. Os sinais ignorados na entrada do shell não podem ser capturados ou redefinidos.

ilkkachu
fonte
Isso também pode ser alcançado no shell atual? (Não está em um script.)
1
Você pode do (trap - INT; something-that-runs-forever)permitir a interrupção do comando. Além disso, você não precisa correr :- você pode apenas usar uma seqüência vazia para ignorar um sinal: trap '' INT. Tudo isso é POSIX, e deve funcionar em qualquer shell compatível (não apenas no Bash).
Toby Speight
Note-se também que a escrita SIGINTna íntegra não é estritamente portátil: " implementações podem permitir nomes com o SIGprefixo ou ignorar caso em nomes de sinal como uma extensão . (Ênfase minha)"
Toby Speight
você pode passar uma string vazia como a ação de ignorar um sinal eg trap "" INT(também POSIX)
daf
@TobySpeight, a razão que eu usei trap :em vez de trap ""foi exatamente isso, para não ter o sinal ignorado (mas torná-lo um não-op vez), de modo que não precisamos fazer mais nada para ser capaz de interromper o principal somethingprograma.
ilkkachu
0

Outra opção é something-that-runs-forevermanipular o sinal (saindo normalmente quando é recebido). Obviamente, só faz sentido quando esse programa é usado em muitos scripts, e o comportamento desejado no CTRL+ Cé sistematicamente o mesmo - para continuar a execução do script.

Dmitry Grigoryev
fonte
ITYM "dorme e reexecute", não "saia normalmente"?
Toby Speight