esperar pelo processo no pipeline retorna código de saída errado

esperar pelo processo no pipeline retorna código de saída errado

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-pide execute:

$ ./wait-pid 
exit code: 124

que é o que eu espero, timeoutencerra o sleepprocesso e sai com 124, que waitretorna 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 waitretornar 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 timeoutquando 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

informação relacionada