Teclas de sinal como Ctrl+ Cenviam um sinal para todos os processos no grupo de processos em primeiro plano .
No caso típico, um grupo de processos é um pipeline. Por exemplo, em head <somefile | sort
, o processo em execução head
e o processo em execução sort
estão no mesmo grupo de processos, assim como o shell, para que todos recebam o sinal. Quando você executa um trabalho em segundo plano ( somecommand &
), esse trabalho está em seu próprio grupo de processos; portanto, pressionar Ctrl+ Cnão o afeta.
O timeout
programa se coloca em seu próprio grupo de processos. Do código fonte:
/* Ensure we're in our own group so all subprocesses can be killed.
Note we don't just put the child in a separate group as
then we would need to worry about foreground and background groups
and propagating signals between them. */
setpgid (0, 0);
Quando ocorre um tempo limite, timeout
passa pelo simples expediente de matar o grupo de processos do qual ele é membro. Como se colocou em um grupo de processos separado, o processo pai não estará no grupo. O uso de um grupo de processos aqui garante que, se o aplicativo filho for dividido em vários processos, todos os seus processos receberão o sinal.
Quando você executa timeout
diretamente na linha de comando e pressiona Ctrl+ C, o SIGINT resultante é recebido pelo timeout
processo filho e por ele, mas não pelo shell interativo, que é timeout
o processo pai do processo. Quando timeout
é chamado de um script, somente o shell que executa o script recebe o sinal: timeout
não o recebe, pois está em um grupo de processos diferente.
Você pode definir um manipulador de sinal em um script de shell com o trap
builtin. Infelizmente, não é assim tão simples. Considere isto:
#!/bin/sh
trap 'echo Interrupted at $(date)' INT
date
timeout 5 sleep 10
date
Se você pressionar Ctrl+ Capós 2 segundos, isso ainda aguarda os 5 segundos completos e imprima a mensagem “Interrompido”. Isso ocorre porque o shell evita executar o código de interceptação enquanto um trabalho em primeiro plano está ativo.
Para remediar isso, execute o trabalho em segundo plano. No manipulador de sinal, chame kill
para retransmitir o sinal para o timeout
grupo de processos.
#!/bin/sh
trap 'kill -INT -$pid' INT
timeout 5 sleep 10 &
pid=$!
wait $pid
bg
defg
comandos. De qualquer forma, existe alguma diferença entre os exemplos 1 e 3?