bloqueio / não bloqueio de pipes / redirecionamentos dentro da substituição de comandos

3

Eu observei o seguinte comportamento no bash:

{ echo 'foo' ; sleep 10 ; }

- > saída padrão "foo" aparece imediatamente, após 10 segundos o comando é feito (como esperado)

{ echo 'foo' ; sleep 10 ; } > >(grep 'oo')

- > saída padrão "foo" aparece imediatamente, após 10 segundos o comando é feito (como esperado)

{ echo 'foo' ; sleep 10 ; } > >(grep 'oo' | grep 'oo')

- > saída padrão "foo" aparece após 10 segundos

{ echo 'foo' ; sleep 10 ; } > >(grep 'oo' >&2)

- > erro padrão "foo" aparece após 10 segundos

Por que a linha de comando com o grep único na saída do comando de substituição é imediatamente resultado, enquanto as variantes com o pipe e o redirecionamento aguardam até o final da suspensão?

    
por user19426 11.08.2017 / 23:21

2 respostas

3

Você não precisa ficar tão chique; você pode observar o mesmo efeito com

{ echo 'foo' ; sleep 10 ; } | grep oo | grep oo

ou

{ echo 'foo' ; sleep 10 ; } | grep oo | cat

ou

  • Abra dois terminais. Vá para o mesmo diretório em ambos (por exemplo, seu diretório inicial ou /tmp ).
  • Em um, faça { echo 'foo' ; sleep 10 ; } | grep oo > foo.out .
  • No outro, faça ls -ld foo.out repetidamente.
    Você verá que o arquivo foo.out aparece imediatamente, mas é o tamanho 0 por dez segundos, após o qual se torna 4 bytes.

Simplesmente: grep testa para ver se sua saída (padrão) é um terminal. Se estiver, grava a saída tão rapidamente quanto a saída para gravar. Se não for, ele armazena em buffer sua saída e grava N bytes por vez, onde N é tipicamente 512, mas pode ser diferente em algumas implementações.

    
por 11.08.2017 / 23:34
1

Estendendo a resposta de Scott:

Compare

 { echo 'foo' ; sleep 3 ; } | grep oo | cat

com

 { echo 'foo' ; sleep 3 ; } | stdbuf -o 0 grep oo | cat
    
por 11.08.2017 / 23:42