为什么“ tail -f…| 尾巴”无法产生任何输出?


36

为什么以下命令不产生任何输出?

$ tail -f /etc/passwd | tail

阅读有关缓冲的内容后,我尝试了以下操作,但无济于事:

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

请注意,以下内容确实会产生输出:

$ tail /etc/passwd | tail

这样:

$ tail -f /etc/passwd | head

我使用的是尾部版本8.21(GNU coreutils)。


17
π的最后10位数字是多少?
基思·汤普森

Answers:


15

我以为我已经在UNIX中看到了一切。这个问题使我自鸣得意。真是个好问题!

tail显示最后的X行。 tail -f这样做是一样的,但本质上是无限循环的:在启动时,显示文件的最后X行,然后使用一些OS魔术(如inotify),监视并显示新行。

要执行其工作,tail必须能够找到文件的末尾。 如果tail找不到文件的结尾,则无法显示最后X行,因为“ last”是未定义的。那么tail在这种情况下该怎么办?等待直到找到文件末尾。

考虑一下:

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

这似乎从未取得进展,因为from永远都没有确定的文件结尾chatter

如果您要求tail提供文件系统管道的最后几行,则会得到相同的行为。考虑:

$ mkfifo test.pipe
$ tail test.pipe

stdbuf解决这个问题是一种崇高的尝试。但是关键事实是I / O缓冲不是根本原因:缺少明确的文件结尾是。如果您查看tail.c源代码,您将看到file_lines函数注释显示为:

END_POS是EOF的文件偏移量(比最后一个字节的偏移量大1)。

这就是魔术。您需要文件尾才能在所有配置中使用tail。 head没有该限制,它只需要一个文件开始(它可能没有,请尝试head test.pipe)。面向流的工具(例如,sed并且awk不需要文件的开头或结尾):它们在缓冲区上工作。


37

tail -f的尾巴实际上是目前未知的东西,所以下一个应该怎么tail知道。另一方面tail -f,头部已经是已知的并且可以被处理。

或更简单地说:tail是相对于文件的末尾,但是输出流tail -f没有EOF(至少在终止之前没有)。

如果你发现第一个tail的PID,并杀死它,你应该看到第二输出。


21

技术答案

当使用流作为输入运行时,tail保留一个n-line缓冲区以在读取流时填充它,但是直到到达流的末尾时才输出这些行,即,EOF当尝试从输入中读取时它会收到特殊代码流。调用tail -f不会退出,因此它将永远不会关闭其流,这使得不可能例如返回该流的最后10行。


3

的功能tail是显示输入或文件的最后一部分-“尾部”。(该选项-f是关于以后的操作的,因此在此不相关。)

让我们考虑一个文件:

文件最后一部分是什么?
假设这是文件的最后n行

当我们读取i输入文件的行时,如何确定是否需要打印?
我们不知道它是否在最后一部分中-因为我们不知道最后一行是哪一行。所以我们现在不能打印。

我们需要一直保持这行,直到清楚这是最后n几行的一部分,或者不再可以成为它的一部分,因为我们知道n更多行

如果现在到文件末尾,我们知道n保留的最后n几行实际上是文件的最后几行。

现在,在

tail -f /etc/passwd | tail

第一个tail读取文件,然后等待从文件中获取更多数据,并将其写出。因此,将没有信号文件的末尾,当涉及到它读取文件的末尾到第二尾巴。否则,第二个文件将tail 永远不会收到文件结尾的通知,因此它永远无法找出应该打印的最后几行。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.