Eu entrei em um estado interessante no Ubuntu. As etapas abaixo descrevem melhor.
Com um único tubo, estou vendo o que espero
# In shell A
tail -f foo.log | grep aaa
# In shell B
echo aaa >> foo.log
# Shell A prints out `aaa`
Mas com vários tubos não estou vendo nada
# In shell A
tail -f foo.log | grep aaa | grep bbb
# In shell B
echo aaa bbb >> foo.log
# Nothing ever prints in shell A
Mas funciona bem se eu estiver apenas ecoando.
echo 'aaa bbb' | grep aaa | grep bbb
Esta é minha tentativa de criar uma reprodução mínima - originalmente encontrei o problema ao tentar tee logs do adb logcat (ferramentas de desenvolvimento do Android). Eu tentei em zsh, bash e fish também.
Presumi que tivesse algo a ver com o limite do inotify watcher, mas ultrapassá-lo não mudou nada.
Isso ocorre por causa do buffer no pipe, que em geral não se preocupa com linhas e pode acumular dados.
Acho que
tail -f
usa o buffer de linha por si só; e o últimogrep
grava no tty, então também usa buffer de linha. Portanto, seu primeiro exemplo funciona.Mas
grep
no meio é diferente e você precisa ajustar seu comportamento forçando o buffer de linha ou desabilitando o buffer. Os comandos abaixo funcionarão conforme o esperado.Se o seu
grep
suporte--line-buffered
(ele faz no Ubuntu):Soluções mais genéricas (funcionarão com muitos filtros diferentes de
grep
):Veja
man 1 grep
,man 1 unbuffer
eman 1 stdbuf
para detalhes e peculiaridades.Notas:
grep --line-buffered
,unbuffer
estdbuf
não são especificadas pelo POSIX).grep --line-buffered
, então deve ser sua escolha. Não adianta usar ferramentas extras.unbuffer
estdbuf
trabalham de maneiras completamente diferentes .stdbuf
, o buffer de linha (-oL
) deve ser preferido a nenhum buffer (-o0
) aqui, porquegrep
escreveu em outro arquivo, ele se comportaria como o outro arquivogrep
. Nesse caso, se você deseja que as linhas apareçam no arquivo final imediatamente, também deve modificar o comportamento do último arquivogrep
.fish
, ifgrep
é uma função wrapper, você pode não obter o comportamento desejado com--line-buffered
. Usecommand grep --line-buffered
. Veja esta pergunta: O tubo de saída espera pelo EOF emfish
.Nota lateral:
tail foo.log | grep aaa | grep bbb
(ou seja,tail
sem-f
) não causa o problema porquetail
sai. Quandotail
sai, o primeirogrep
detecta EOF, libera seu buffer e sai, então o segundogrep
faz o mesmo.