Se você quisesse executar os consumidores e o produtor em paralelo, mas serializasse a saída dos consumidores, seria necessário atrasar a saída do segundo consumidor. Para isso, você precisa armazenar sua saída de alguma forma e a melhor maneira é com um arquivo temporário.
com zsh
:
{cat =(producer > >(consumer1 >&3) | consumer2)} 3>&1
bash
tem um problema, pois não espera pelos comandos de substituição do processo, portanto, é necessário usar métodos de trabalho desagradáveis .
Aqui, usamos a forma =(...)
de substituição de processo para armazenar a saída de comsumer2
em um arquivo temporário e cat
depois. Não podemos fazer isso por mais de dois consumidores. Para isso, precisaríamos criar os arquivos temporários manualmente.
Quando não estivermos usando =(...)
, teremos que manipular a limpeza dos arquivos temporários manualmente. Podemos lidar com isso criando e excluindo-os na frente para não termos que nos preocupar com os casos em que o script é morto. Ainda com zsh
:
tmp1=$(mktemp) && tmp2=$(mktemp) || exit
{
rm -f -- $tmp1 $tmp2
producer > >(consumer1) > >(consumer2 >&3) > >(consumer3 >&5)
cat <&4 <&6
} 3> $tmp1 4< $tmp1 5> $tmp2 6< $tmp2
Editar (eu inicialmente perdi o fato de que uma solução para dash
era necessária)
Para dash
(ou qualquer shell POSIX que não defina o sinalizador close-on-exec em fds acima de 2 e use pipes e não pares de soquetes para |
) e em sistemas com /dev/fd/x
support:
tmp1=$(mktemp) && tmp2=$(mktemp) || exit
{
rm -f -- "$tmp1" "$tmp2"
{
{
{
producer | tee /dev/fd/4 /dev/fd/6 | consumer1 >&7
} 4>&1 | consumer2 >&3
} 6>&1 | consumer3 >&5
} 7>&1
cat - /dev/fd/6 <&4
} 3> "$tmp1" 4< "$tmp1" 5> "$tmp2" 6< "$tmp2"
Isso funcionaria com dash
, bash
, zsh
, mksh
, busybox sh
, posh
no Linux, mas não ksh93
. Essa abordagem não pode ir além de 4 consumidores, pois estamos limitados a fds de 0 a 9.