sh
Sessão shell interativa :
$ sh
$ timeout 1 yes | sed -n s/a/b/p ; echo $?
Terminated
143
$
Script não interativo via sh -c
:
$ sh -c 'timeout 1 yes | sed -n s/a/b/p ; echo $?'
0
$
Por que esses dois exemplos produzem códigos de saída diferentes?
timeout
(pelo menos GNUtimeout
), por padrão, tenta executar o comando em um novo grupo de processos e mata esse grupo de processos com SIGTERM após o tempo limite.Dessa forma, se esse comando gerar mais processos, eles também serão eliminados após o tempo limite.
Veja
timeout
fazendo umsetpgid(0, 0)
(o mesmo quesetpgrp()
) para criar um novo grupo de processos, você o vê fazendokill(316060, SIGTERM)
para matarsleep 2
, mas tambémkill(0, SIGTERM)
para matar seu próprio grupo de processos (que foi criado anteriormente) que também teria matado processos gerados por,sleep 2
se houver (nenhum neste caso ).Agora, quando o controle de tarefas estiver ativado no shell (como quando interativo ou chamado com a opção
-m
/-o monitor
), em:O shell já inicia
timeout
esleep 3
em um novo grupo de processos, e na maioria dos shells, o líder do grupo de processos será aquele que executatimeout
.Então, quando
timeout
fazsetpgrp()
, igual asetpgid(0, 0)
, não criará um novo grupo de processos, que apenas se tornará um no-op. Portanto, o grupo de processos ainda conterátimeout
, o processo que ele gera para executarsleep 2
esleep 3
que foi colocado lá anteriormente pelo shell.Desta vez, o
kill(0, SIGTERM)
mata o processo em execuçãosleep 3
, pois também está no grupo de processos 318594 (conforme colocado lá pelo shell comsetpgid(318595, 318594)
).Em:
Você descobrirá que o pipeline dura 4 segundos e só
sleep 3
é encerrado após 1 segundo, pois desta vez, o grupo de processos criado pelo shell é liderado pelo processo em execuçãosleep 2
, portantotimeout
, é capaz de criar um novo grupo de processos para si (e seu filhosleep 3
) que é diferente do grupo de processos criado pelo shell para os 3 comandos no pipeline (e, como resultado, você descobrirá que Ctrl+ Cou Ctrl+ Znão funcionam corretamente durantetimeout
a execução, poistimeout
não estão sendo executados no grupo de processos em primeiro plano )Quando executado com
--foreground
,timeout
pula a criação desse grupo de processos extra e não faz umkill(0, SIGTERM)
para eliminar seu próprio grupo de processos, portanto, o comportamento é mais consistente, mas significa que os processos netos não são eliminados.sh
é morto, mas nãosleep 2
.Isso também explica por que em um shell interativo em um terminal:
Ou:
cat
não pode ler a partir do terminal. Ele acaba sendo suspenso quando tenta, pois está em um novo grupo de processos, portanto não mais no grupo de processos de primeiro plano do terminal.Novamente, adicionar a
--foreground
opção evita o problema.