Estou tentando usar um pipe nomeado para poder manter stdout
a saída de status de um processo longo. Eu poderia usar stderr
para saída de status, mas gostaria de manter isso para erros. Aqui está um exemplo:
#!/bin/bash
pipe=$(mktemp -u)
mkfifo $pipe
dd if=/dev/zero of=$pipe bs=1M count=1024 status=progress & cat $pipe > test.bin
# ¿¿¿ Status of dd command ???
rm $pipe
O comando não é exatamente o que estou tentando fazer, mas ilustra a combinação de usar um pipe nomeado para a saída de um processo alimentando a entrada de outro. No meu aplicativo, dd
é substituído por algum comando de longa duração e cat
por ssh
. Isso faria o que eu quero, mas não sei como obter o status do dd
comando, pois $?
retornaria o status do cat
comando. Se isso fosse um pipe, eu poderia usar, PIPESTATUS
mas isso não parece funcionar para processos paralelos. No aplicativo real, um (ou ambos) os comandos podem falhar.
Existe uma maneira de obter o status dos processos executados em paralelo? Existe uma maneira melhor de realizar essa tarefa usando algo diferente de pipes nomeados?
Para obter o status de saída de um comando assíncrono, você usa
wait
em seu pid:(também corrigindo alguns dos erros óbvios, como não verificar o sucesso daqueles
mktemp
/mkfifo
, expansões não citadas,--
s ausentes).Observe que se
dd
(ou qualquer comando real quedd
esteja substituindo no seu caso) sair antes de abrir$pipe
para gravação, ele travarácat
em seu próprio arquivo somente leituraopen()
do fifo indefinidamente.Para contornar isso, você pode ter o shell aberto
$pipe
em outro fd para o processo que eventualmente será executadodd
, certificando-se de que o pipe seja instanciado assim que ocat
abrir também (e supondodd
que não feche arbitrariamente esse fd antes de abrir$pipe
):Da mesma forma, se
cat
morrer antes de abrir o cano, você terá o mesmo problema simétrico, que pode ser resolvido da mesma maneira.Em vez de um pipe nomeado, se o seu sistema tiver arquivos, você provavelmente também poderá usar um pipe normal em combinação com e usar 's para recuperar os status de saída:
/dev/fd/n
/dev/fd/n
bash
$PIPESTATUS
(
$PIPESTATUS
é específico do bash, mas existem alternativas para outros shells).Acima, ambos
dd
ecat
terão o pipe aberto em seu fd 3 (o final de escrita paradd
e o final de leitura paracat
) e eles abrirão/dev/fd/3
dando a eles outro fd no pipe como na solução acima. Usamos fds 4 e 5 para restaurar o stdin e stdout originais para ambos (embora aquicat
stdout vá paratest.bin
).