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 heade o processo em execução sortestã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 timeoutprograma 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, timeoutpassa 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 timeoutdiretamente na linha de comando e pressiona Ctrl+ C, o SIGINT resultante é recebido pelo timeoutprocesso filho e por ele, mas não pelo shell interativo, que é timeouto processo pai do processo. Quando timeouté chamado de um script, somente o shell que executa o script recebe o sinal: timeoutnã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 trapbuiltin. 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 killpara retransmitir o sinal para o timeoutgrupo de processos.
#!/bin/sh
trap 'kill -INT -$pid' INT
timeout 5 sleep 10 &
pid=$!
wait $pid
bgdefgcomandos. De qualquer forma, existe alguma diferença entre os exemplos 1 e 3?