tail 是否读取整个文件?

The*_*Cat 115 tail

如果我想要tail一个 25 GB 的文本文件,该tail命令会读取整个文件吗?

由于文件可能分散在磁盘上,我想它必须如此,但我不太了解这种内部结构。

jll*_*gre 120

不,tail不读取整个文件,它会一直寻找到最后,然后向后读取块,直到达到预期的行数,然后以正确的方向显示行,直到文件结束,并可能继续监视如果使用该-f选项,则为文件。

但是请注意,tail如果提供了不可搜索的输入,则别无选择,只能读取整个数据,例如从管道读取时。

同样,当要求从文件开头查找行时,如果支持使用tail -n +linenumber语法或tail +linenumber非标准选项,tail显然会读取整个文件(除非被中断)。

  • 该死,太快了:-)。这是[相关源代码](http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/tail.c#n464)。*打印文件 FD 末尾的最后 N_LINES 行。向后遍历文件,一次读取 'BUFSIZ' 字节(可能除了第一个),直到我们到达文件的开头或读取了 NUMBER 个换行符。* (14认同)
  • 请注意,并非所有 `tail` 实现都这样做或正确执行。例如,busybox 1.21.1 `tail` 在这方面被破坏了。另请注意,当`tail`ing stdin 并且stdin 是常规文件并且文件中的初始位置不在调用`tail` 时的开头时,行为会有所不同(例如在`{ cat > /dev/null; tail ; } <文件`) (4认同)
  • @StephaneChazelas *nix - 奇怪的边缘情况的世界变得正常。(尽管可搜索与不可搜索的输入绝对是一个有效的观点。) (4认同)

小智 70

你可以亲眼看到它是如何tail工作的。正如你可以为我的一个文件read完成 3 次,总共读取大约 10K 字节:

strace 2>&1  tail ./huge-file >/dev/null  | grep -e "read" -e "lseek" -e "open" -e "close"
open("./huge-file", O_RDONLY)           = 3
lseek(3, 0, SEEK_CUR)                   = 0
lseek(3, 0, SEEK_END)                   = 80552644
lseek(3, 80551936, SEEK_SET)            = 80551936
read(3, ""..., 708) = 708
lseek(3, 80543744, SEEK_SET)            = 80543744
read(3, ""..., 8192) = 8192
read(3, ""..., 708) = 708
close(3)                                = 0
Run Code Online (Sandbox Code Playgroud)

  • `strace` 显示系统调用 `tail` 在运行时所做的事情。关于系统调用的一些介绍,你可以在这里阅读 http://en.wikipedia.org/wiki/System_call。简而言之 - 打开 - 打开一个文件并返回一个句柄(在本例中为 3),`lseek` 位置你要读取的位置,`read` 只是读取,正如你所看到的,它返回读取了多少字节, (11认同)
  • 因此,分析系统调用有时可以了解程序的工作原理。 (2认同)

ale*_*xis 26

由于文件可能分散在磁盘上,我想它必须[按顺序读取文件],但我不太了解这种内部结构。

正如您现在知道的,tail只是寻找到文件的末尾(使用系统调用lseek),然后向后工作。但是在上面引用的评论中,您想知道“tail 如何知道磁盘上的哪个位置可以找到文件的结尾?”

答案很简单:Tail 不知道。用户级进程将文件视为连续流,因此所有人都tail可以知道从文件开头的偏移量。但是在文件系统中,文件的“inode”(目录条目)与表示文件数据块物理位置的数字列表相关联。当您从文件中读取时,内核/设备驱动程序会找出您需要的部分,计算出它在磁盘上的位置并为您获取它。

这就是我们拥有操作系统的那种东西:所以你不必担心你的文件块分散在哪里。