Eu achei que já tinha visto tudo no UNIX. Essa pergunta me tirou da minha presunção. Que ótima pergunta!
tail
mostra as últimas linhas X. tail -f
faz o mesmo, mas essencialmente em um loop infinito: na inicialização, mostra as últimas X linhas do arquivo, depois usa alguma mágica do SO (como inotify), monitora e mostra novas linhas.
Para fazer seu trabalho, tail
deve conseguir localizar o final do arquivo. Se tail
não puder encontrar o final do arquivo, ele não poderá mostrar as últimas X linhas, porque "último "é indefinido. Então, o que o tail
faz nesse caso? Aguarda até encontrar o final do arquivo.
Considere isso:
$ chatter() { while :; do date; sleep 1; done; }
$ chatter | tail -f
Isso nunca parece progredir, porque nunca há um final definido de arquivo de chatter
.
Você obtém o mesmo comportamento se solicitar que tail
forneça as últimas linhas de um canal do sistema de arquivos. Considere:
$ mkfifo test.pipe
$ tail test.pipe
stdbuf
para contornar o problema percebido foi uma tentativa nobre. O fato-chave é que o buffer de E / S não é a causa raiz: a falta de um fim-de-arquivo definido é. Se você conferir o código-fonte tail.c , você veja o comentário da função file_lines
:
END_POS is the file offset of EOF (one larger than offset of last byte).
e essa é a mágica. Você precisa de um fim de arquivo para que a cauda funcione em qualquer configuração. head
não tem essa restrição, só precisa de um início de arquivo (o que talvez não tenha feito, tente head test.pipe
). As ferramentas orientadas por fluxo, como sed
e awk
, não precisam de um início nem de um final de arquivo: elas funcionam em buffers.