Eu devo estar esquecendo algo aqui:
#!/bin/bash
timeout 5 sleep 10 &
parent_pid=$( ps --pid $! -o ppid --no-headers )
timeout_pid=$( pgrep --parent $parent_pid timeout )
wait $timeout_pid
echo "exit code: $?"
Chame o script wait-pid
e execute:
$ ./wait-pid
exit code: 124
que é o que eu espero, timeout
encerra o sleep
processo e sai com 124, que wait
retorna obedientemente.
Mas se eu adicionar um pipeline ao comando inicial:
timeout 5 sleep 10 | cat &
parent_pid=$( ps --pid $! -o ppid --no-headers )
timeout_pid=$( pgrep --parent $parent_pid timeout )
wait $timeout_pid
echo "exit code: $?"
agora eu recebo:
$ ./wait-pid
exit code: 0
Ainda não deve wait
retornar o código de saída do processo que está aguardando: timeout
. Portanto, o código de saída ainda não deveria ser 124.
Isso ocorre com o lançamento do bash 4.4.20(1).
Responder1
Recebi uma resposta do super conhecedor Greg Wooledge na lista de discussão do bash. O elemento chave é:
O comando wait funciona apenas em processos filhos diretos do shell, também conhecidos como "comandos assíncronos". No caso em que seu comando assíncrono é um pipeline, voltamos ao conjunto de recursos sh original. O status de saída do seu comando assíncrono é o do último comando no pipeline, e os status de saída dos outros comandos são simplesmente descartados.
É por isso que não recebo o código de saída timeout
quando ele está em um pipeline.
A maneira de obter o comportamento desejado é usar um arquivo temporário para capturar códigos de saída de dentro do código assíncrono. Algo como:
{
timeout 5 sleep 10 | cat
echo "${PIPESTATUS[@]}" > "$tempfile"
} &
wait