Dado este exemplo mínimo
( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; )
ele gera LINE 1
e, depois de um segundo, saídas LINE 2
, como esperado .
Se canalizarmos isso para grep LINE
( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep LINE
o comportamento é o mesmo do caso anterior, conforme o esperado .
Se, alternativamente, canalizarmos isso para cat
( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | cat
o comportamento é novamente o mesmo, como esperado .
No entanto , se canalizarmos para grep LINE
, e depois para cat
,
( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep LINE | cat
não há saída até que um segundo passe e as duas linhas apareçam na saída imediatamente, o que eu não esperava .
Por que isso está acontecendo e como posso fazer com que a última versão se comporte da mesma maneira que os três primeiros comandos?
cat
concatena arquivos. O que você está tentando fazer canalizandocat
?cat
simplesmente lêstdin
e envia parastdout
. Claro, eu vim com essa pergunta com um monte de coisas complexas no lugar deecho
ecat
, mas elas se mostraram irrelevantes, pois o problema aparece com exemplos muito mais simples.Respostas:
Quando a
grep
saída (pelo menos GNU) não é um terminal, ela armazena em buffer sua saída, que é o que causa o comportamento que você está vendo. Você pode desativar isso usandogrep
a--line-buffered
opção do GNU :ou o
stdbuf
utilitário:Desativar o buffer no tubo tem mais sobre este tópico.
fonte
Explicação simplificada
Como muitos utilitários, isso não é algo peculiar a um programa,
grep
varia sua saída padrão entre o buffer de linha e o buffer total . No primeiro caso, os buffers da biblioteca C emitem dados na memória até que o buffer que contém esses dados seja preenchido ou um caractere de avanço de linha seja adicionado a ele (ou o programa termine corretamente), após o que ele chamawrite()
para realmente gravar o conteúdo do buffer. Neste último caso, apenas o buffer da memória que fica cheio (ou o programa que termina corretamente) aciona owrite()
.Explicação mais detalhada
Essa é a explicação bem conhecida, mas um pouco errada. De fato, a saída padrão não é de buffer de linha, mas de buffer inteligente nas bibliotecas GNU C e BSD C. A saída padrão também é liberada quando a leitura da entrada padrão esgota seu buffer de memória (da entrada pré-leitura) e a biblioteca C precisa chamar
read()
para buscar mais alguma entrada e está lendo o início de uma nova linha. (Uma razão para isso é evitar conflito quando outro programa se conecta a ambas as extremidades de um filtro e espera poder operar linha por linha, alternando entre gravar no filtro e ler a partir dele; como "coprocesses" no GNUawk
por exemplo.)Influência da biblioteca C
grep
e os outros utilitários fazem isso - ou, mais estritamente, as bibliotecas C que eles usam fazem isso, porque esse é um recurso definido da programação na linguagem C - com base no que eles detectam ser sua saída padrão. Se (e somente se) não for um dispositivo interativo, eles escolherão o buffer completo, caso contrário, eles escolherão o buffer inteligente. Um canal não é considerado um dispositivo interativo, porque a definição de ser um dispositivo interativo, pelo menos no mundo do Unix e Linux, é essencialmente oisatty()
chamada retornando true para o descritor de arquivo relevante.Soluções alternativas para desativar o buffer completo
Alguns utilitários, como
grep
opções idiossincráticas, como--line-buffered
essa, alteram essa decisão, que, como você pode ver, tem um nome errado. Mas uma fração muito pequena dos programas de filtro que se pode usar realmente tem essa opção.De maneira mais geral, pode-se usar ferramentas que vasculham as partes internas específicas da biblioteca C e alteram sua tomada de decisão (que têm problemas de segurança se o programa a ser alterado for UID definido, além de serem específicas de bibliotecas C específicas e, de fato, serem específicos para programas escritos ou em camadas sobre a linguagem C), ou ferramentas como essas
ptybandage
que não alteram as partes internas do programa, mas simplesmente interpõem um pseudo-terminal como saída padrão, para que a decisão saia como "interativa", para afetar isso.Leitura adicional
fonte
grep
, mas das chamadas de biblioteca subjacentes,setbuf
/setvbuf
. Não conheço uma referência on-line confiável para o padrão C, mas, por exemplo, as páginas de manual do Linux e FreeBSD, juntamente com a descrição do POSIX,setvbuf
chamam "line buffered". Até a constante simbólica é_IOLBF
.Usar
para fazer com que o grep não armazene em buffer mais de uma linha por vez.
fonte