Por que “tail -f… | cauda ”não consegue produzir qualquer saída?

34

Por que o seguinte comando não produz saída?

$ tail -f /etc/passwd | tail

Depois de ler sobre o buffer , tentei o seguinte sem sucesso:

$ tail -f /etc/passwd | stdbuf -oL tail

Observe que o seguinte produz saída:

$ tail /etc/passwd | tail

Então faz isso:

$ tail -f /etc/passwd | head

Estou usando a versão de cauda 8.21 (GNU coreutils).

    
por thomie 10.09.2014 / 19:01

4 respostas

13

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.

    
por 11.09.2014 / 18:49
35

A cauda de tail -f é realmente algo desconhecido no presente, então como o próximo tail deve saber. Por outro lado, a cabeça de tail -f é algo já conhecido e poderia ser processado.

Ou, para simplificar: tail é relativo ao final do arquivo, mas o fluxo de saída de tail -f não recebeu EOF (pelo menos não antes de sua finalização).

Se você encontrar o primeiro pid de tail e o matar, você deve então ver a saída do segundo.

    
por 10.09.2014 / 19:07
21

Resposta técnica

Ao executar com um fluxo como entrada, tail mantém um buffer n -line que preenche enquanto lê o fluxo, mas não pode produzir essas linhas até atingir o final do fluxo, ou seja, ele recebe um fluxo código EOF especial ao tentar ler a partir do fluxo de entrada. A invocação tail -f não sai, por isso nunca fechará o seu fluxo, o que torna impossível, e. retorne as 10 últimas linhas desse fluxo.

    
por 10.09.2014 / 23:41
3

A função tail é mostrar a última parte - "tail" - da entrada ou arquivo. (A opção -f é sobre o que faz depois, então isso não é relevante aqui.)

Vamos pensar em um arquivo:

Qual é a última parte de um arquivo ?
Digamos que são as últimas n linhas de um arquivo.

Quando lemos a linha i do arquivo de entrada, como decidir se precisa ser impresso ou não?
Não sabemos se está na última parte - porque não sabemos qual será a última linha. Então, não podemos imprimi-lo agora.

Precisamos manter a linha até que fique claro que ela faz parte das últimas n linhas ou não pode mais fazer parte dela, porque sabemos n linhas adicionais

Se chegarmos agora ao fim do arquivo , saberemos que as últimas n linhas que mantemos são, na verdade, as últimas n linhas do arquivo.

Agora, no caso de

tail -f /etc/passwd | tail

o primeiro tail lê o arquivo e aguarda para obter mais dados dele, para escrever isso também. Por isso, não sinalizará um fim de arquivo para a segunda cauda quando se trata do final do arquivo que ele lê. Sem isso, o segundo tail nunca é notificado do final do arquivo, então ele pode nunca descobrir quais são as últimas linhas que ele deve imprimir.

    
por 14.09.2014 / 11:15

Tags