tee envia dados incompletos

1
$ head -c10G /dev/zero |
  tee >(head -c1M | wc -c) >(head -c10M | wc -c) >(head -c100M | wc -c) >(head -c1000M | wc -c)

dá:

1048576
1064960
1064960
1064960

Eu teria esperado:

1048576
10485760
104857600
1048576000

Eu imagino que seja devido a head -c1M fechar o pipe e tee , então, só escreve um bloco a mais nos outros processos, antes de descobrir que não pode gravar no primeiro processo e sair.

Posso pedir ao tee para pular o receptor fechado, mas continuar escrevendo para os outros?

    
por Ole Tange 06.10.2018 / 10:23

3 respostas

3

Você deve usar tee --output-error=exit-nopipe . Isso ignoraria o erro SIGPIPE e EPIPE de gravação, mas ainda morreria em outros erros.

tee --output-error=exit-nopipe , assim como o warn variant da sua resposta, sai quando não pode gravar em pelo menos uma das suas saídas; mas conta a saída padrão como um deles.

Seus exemplos são problemáticos, porque eles simplesmente despejam a saída de head -c10G /dev/zero | tee ... em seu terminal (que você não pode ver porque o byte nulo é "invisível"); e é por isso que o tee em sua resposta não sai: porque ele ainda estará gravando para stdout depois que as substituições do processo >(...) tiverem saído.

Para sistemas sem GNU tee, uma solução possível é incluir cat >/dev/null nos comandos para os quais a saída de tee é canalizada; mas você não pode fazer isso com todos eles; você terá que decidir sobre uma saída "master" que fará com que tee seja encerrado se a gravação não for bem-sucedida. Exemplo:

$ dd if=/dev/zero |
  tee >(dd of=/dev/null count=200; cat >/dev/null) >(dd of=/dev/null count=700; cat >/dev/null) |
  dd of=/dev/null count=1000
$ dd if=/dev/zero |
  tee >(dd of=/dev/null count=1000) >(dd of=/dev/null count=700; cat >/dev/null) |
  { dd of=/dev/null count=200; cat >/dev/null; }

Ambos devem escrever 200, 700 e 1000 blocos, respectivamente.

    
por 08.10.2018 / 12:21
0

Parece que --output-error=warn faz isso.

head -c10G /dev/zero |
  tee --output-error=warn >(head -c10M | wc -c) >(head -c100M | wc -c) >(head -c1000M | wc -c)

Infelizmente, ele também causa avisos no stderr e não sai se não puder gravar em nenhum deles.

    
por 06.10.2018 / 10:26
0

Acontece que qualquer canal que bloqueie enviará um SIGPIPE para tee e parará:

$ head -c10G /dev/zero |   tee >(head -c10 | wc -c) >(head -c1M | wc -c)
10
65536

O comando tee está recebendo o SIGPIPE do primeiro canal e fazendo com que todos os filhos saiam.

Você precisaria expandir cada canal para não ter limite:

$ head -c10G /dev/zero |   tee >({ head -c10 | wc -c; }; cat >/dev/null )  >(head -c1M | wc -c)
10
1048576

para todos os casos que você deu:

$ head -c10G /dev/zero |   tee >({ head -c1M | wc -c;}; cat >/dev/null) >({ head -c10M | wc -c; }; cat >/dev/null) >( { head -c100M | wc -c; }; cat>/dev/null) >(head -c1000M | wc -c)
1048576
10485760
104857600
1048576000

Mas é mais simples informar tee para evitar a saída de erros de pipe com a opção -p :

$ head -c10M /dev/zero |   tee -p >(head -c10 | wc -c) >(head -c100 | wc -c) >(head -c1000| wc -c) >(head -c1M | wc -c)
100
1000
10
1048576

Que pode ser impresso fora de ordem.

    
por 08.10.2018 / 13:09

Tags