Por que “tail -f… | cauda "falhar em produzir alguma saída?

36

Por que o comando a seguir não produz nenhuma 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

O mesmo acontece com isso:

$ tail -f /etc/passwd | head

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

Thomie
fonte
17
Quais são os últimos 10 dígitos de π?
Keith Thompson

Respostas:

15

Eu pensei que tinha visto tudo no UNIX. Esta pergunta me tirou da minha presunção. Que ótima pergunta!

tailmostra as últimas X linhas. tail -ffaz o mesmo, mas essencialmente em um loop infinito: na inicialização, mostre as últimas X linhas do arquivo e, em seguida, use alguma mágica do SO (como inotify), monitore e mostre novas linhas.

Para fazer seu trabalho, taildeve ser capaz de localizar o final do arquivo. Se tailnão conseguir encontrar o final do arquivo, ele não poderá mostrar as últimas linhas X, porque "last" não está definido. Então, o que tailfaz neste caso? Espera até encontrar o final do arquivo.

Considere isto:

$ chatter() { while :; do date; sleep 1; done; }
$ chatter | tail -f

Isso nunca parece fazer progresso, porque nunca existe um final definido de arquivo chatter.

Você obtém o mesmo comportamento se solicitar tailas últimas linhas de um canal do sistema de arquivos. Considerar:

$ mkfifo test.pipe
$ tail test.pipe

stdbufcontornar o problema percebido foi uma tentativa nobre. O fato principal é que o buffer de E / S não é a causa principal: a falta de um final de arquivo definido é. Se você verificar o código-fonte tail.c , verá o file_linescomentário da função:

END_POS é o deslocamento do arquivo EOF (um maior que o deslocamento do último byte).

e essa é a mágica. Você precisa de um final de arquivo para que o tail funcione em qualquer configuração. headnão possui essa restrição, apenas precisa do início do arquivo (o que pode não ter, tente head test.pipe). As ferramentas orientadas para o fluxo gostam sede awknão precisam nem do início nem do fim do arquivo: elas funcionam em buffers.

bispo
fonte
37

tail -fO rabo de na verdade é algo desconhecido no presente, então como o próximo deve tailsaber. Por outro lado tail -f, a cabeça já é algo conhecido e pode ser processado.

Ou, para simplificar: tailé relativo ao final do arquivo, mas o fluxo de saída tail -fnão possui EOF (pelo menos não antes de seu término).

Se você encontrar a primeira tail's pid e matá-lo, você deve então ver a saída do segundo.

Ghanima
fonte
21

Resposta técnica

Ao executar com um fluxo como entrada, tail mantém um nbuffer de linha que ele preenche ao ler o fluxo, mas não pode gerar essas linhas até chegar ao final do fluxo, ou seja, recebe um EOFcódigo especial ao tentar ler a entrada corrente. A invocação tail -fnão sai e, portanto, nunca fecha seu fluxo, o que torna impossível, por exemplo, retornar as 10 últimas linhas desse fluxo.

sleblanc
fonte
3

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

Vamos pensar em um arquivo:

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

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

Precisamos manter a linha até que fique claro que é parte dos últimosn linhas, ou que não pode mais fazer parte dela, porque sabemos noutras linhas

Se agora chegamos ao final do arquivo , sabemos que as últimas nlinhas que mantemos são, de fato, as últimasn linhas do arquivo.

Agora, no caso de

tail -f /etc/passwd | tail

o primeiro taillê o arquivo e, em seguida, espera obter mais dados dele para escrevê-lo também. Portanto, ele não sinalizará o final do arquivo para a segunda cauda quando chegar ao final do arquivo que ele lê. Sem isso, o segundo tail nunca é notificado sobre o final do arquivo, portanto nunca pode descobrir quais são as últimas linhas que deve imprimir.

Volker Siegel
fonte