Tail:输出文件的最后部分
tail 命令默认打印每个文件的最后部分(默认为10行); 如果没有提供文件名或者提供了一个名为'-'的文件,则从标准输入读取。概述:
tail [option]… [file]…
退出状态为零表示成功,非零值表示失败。
如果指定了多个文件,则在每个文件的输出之前,tail 命令会打印一个一行的文件头,格式如下:
==> file name <==
为了进一步处理 tail 命令的输出,可以将文件头转换为行前缀,可以使用下面的方法实现:
tail … | awk ' /^==> .* <==$/ {prefix=substr($0,5,length-8)":"; next} {print prefix$0} ' | …
GNU 版本的 tail 命令可以输出任意数量的数据(其他版本的 tail 命令可能不行)。它也没有 -r 选项(反向打印),因为将文件反向打印实际上是与打印文件末尾不同的任务;而 BSD 版本的 tail 命令(带有 -r 选项)只能反向打印文件,而文件的大小不能超过其缓冲区大小,通常为 32 KiB。一个更可靠和多功能的反向打印文件的方法是使用 GNU 版本的 tac 命令。
该程序接受以下选项。也请参阅通用选项。
'-c [+]num'
'--bytes=[+]num'
输出最后的 num 个字节,而不是最后的行。然而,如果 num 前面带有'+',则从每个文件的开头字节 num 开始打印,而不是从文件末尾开始。num 可以是以下乘法后缀之一,或者是一个可选整数后跟以下乘法后缀之一:
'b' => 512 ("blocks") 'KB' => 1000 (KiloBytes) 'K' => 1024 (KibiBytes) 'MB' => 1000*1000 (MegaBytes) 'M' => 1024*1024 (MebiBytes) 'GB' => 1000*1000*1000 (GigaBytes) 'G' => 1024*1024*1024 (GibiBytes)
以此类推,'T', 'P', 'E', 'Z', 'Y', 'R', 和 'Q' 等。也可以使用二进制前缀:'KiB'='K','MiB'='M',以此类推。
'-f'
'--follow[=how]'
循环读取文件末尾的更多字符,持续追踪文件的增长。如果指定了多个文件,当从不同的文件获取输出时,tail 会打印一个文件头,以指示该输出来自哪个文件。
有两种方法可以指定如何使用此选项跟踪文件,但只有在所跟踪的文件被删除或重命名时才会注意到这种差异。如果希望在文件被取消链接后仍然追踪增长的文件末尾,请使用 --follow=descriptor。这是默认行为,但如果要跟踪可能被轮换的日志文件(删除或重命名,然后重新打开),则不适用。在这种情况下,使用 --follow=name 来跟踪指定的文件,可以通过定期重新打开文件来查看是否已被其他程序删除并重新创建。请注意,基于 inotify 的实现可以处理此情况,无需定期重新打开文件。
无论使用哪种方法,如果确定所跟踪的文件已经缩小,tail 会打印一条消息,表明文件已被截断,并从文件的开始重新跟踪,假设文件已被截断为 0,这是日志文件的常见截断操作。
当文件被删除时,tail 的行为取决于是按名称还是按描述符进行跟踪。按名称跟踪时,tail 可以检测到文件已被删除,并给出相应的消息,如果指定了 --retry 选项,则会继续定期检查文件是否重新出现。按描述符跟踪时,tail 不会检测到文件已被取消链接或重命名,也不会发出任何消息;即使文件通过其原始名称不再可访问,它可能仍在增长。
选项值 'descriptor' 和 'name' 只能在长格式的选项中指定,不能与 -f 一起使用。
如果没有指定文件操作数且标准输入是 FIFO 或管道,则忽略 -f 选项。同样,如果指定的操作数为 '-',并且标准输入是 FIFO 或管道,则 -f 选项无效。
在具有内核 inotify 支持的情况下,输出会在文件更改时触发,通常非常及时。否则,tail 在检查之间会休眠一秒钟 - 使用 --sleep-interval=n 来更改默认值 - 这可能会使输出看起来稍微不太响应或突发。当使用没有 inotify 支持的 tail 时,可以通过使用亚秒级的睡眠间隔使其更具响应性,例如,通过以下别名:
alias tail='tail -s.1'
'-F'
该选项等同于 --follow=name --retry。也就是说,当文件被删除时,tail 将尝试重新打开它。如果重新打开失败,tail 将不断尝试,直到文件再次可访问为止。
'--max-unchanged-stats=n'
按名称跟踪文件时,如果有 n(默认为 n=5)个连续的迭代,文件未发生变化,则打开/获取文件状态以确定文件名是否仍与以前的设备/索引节点对应。当跟踪正在轮换的日志文件时,这大致是 tail 打印出旋转前最后一行和打印出积累在新日志文件中的行之间的秒数。这个选项只在轮询(即无 inotify)和按名称跟踪时才有意义。
'-n [+]num'
'--lines=[+]'
输出最后的 num 行。然而,如果 num 前面带有'+',则从每个文件的第 num 行开始打印,而不是从末尾开始。大小乘法后缀与 -c 选项相同。
'--pid=pid'
当按名称或描述符跟踪时,可以指定唯一写入所有文件参数的进程 ID(pid)。然后,在该进程终止后不久,tail 也将终止。这只在写入者和跟踪进程在同一台机器上运行时才有效。例如,如果您通过以下方式调用 make 和 tail 来保存构建输出到文件并监视文件增长,则 tail 进程将在构建完成时停止。如果没有此选项,您将不得不手动杀死 tail -f 进程。
$ make >& makerr & tail --pid=$! -f makerr
如果指定的 pid 没有在使用,或者与写入到被跟踪文件的进程不对应,那么 tail 可能会在任何文件停止增长之前终止,或者在实际的写入进程终止之后很久才终止。请注意,一些系统可能不支持 --pid;如果是这种情况,tail 将打印警告信息。
'-q'
'--quiet'
'--silent'
不打印文件名头。
'--retry'
无限尝试打开指定文件。此选项主要在跟踪文件时有用(否则会发出警告)。
当按文件描述符跟踪(即使用 --follow=descriptor)时,此选项只影响文件的初始打开,一旦成功打开,tail 将开始跟踪文件描述符。
当按名称跟踪(即使用 --follow=name)时,tail 无限次尝试重新打开给定的文件,直到被终止。
如果没有此选项,当 tail 遇到不存在或无法访问的文件时,会报告该事实,并且不再检查该文件。
'-s number'
'--sleep-interval=number'
更改迭代之间等待的秒数(默认为 1.0)。在一次迭代中,会检查每个指定的文件是否已更改大小。当 tail 使用 inotify 时,通常会忽略此与轮询相关的选项。然而,如果您同时指定 --pid=p,tail 将检查进程 p 是否至少每 number 秒存活一次。number 必须是非负数,并且可以是当前区域设置或 C 区域设置下的浮点数。参见浮点数。
'-v'
'--verbose'
始终打印文件名头。
'-z'
'--zero-terminated'
使用零字节而不是换行符(ASCII LF)来分隔项目。即,将输入视为由 ASCII NUL 分隔的项目,并以 ASCII NUL 终止输出的项目。此选项可与 'perl -0' 或 'find -print0' 和 'xargs -0' 结合使用,以可靠地处理任意文件名(甚至包含空格或其他特殊字符的文件名)。
为了兼容性,tail 还支持一种过时的用法 'tail -[num][bcl][f] [file]',只有在不与上述用法冲突时才能识别。这种过时的形式只使用一个选项和最多一个文件。在选项中,num 是一个可选的十进制数,后面可以跟一个大小字母('b'、'c'、'l'),表示按 512 字节块、字节或行计数,还可以选择后面跟一个 'f',其含义与 -f 相同。
在不符合 POSIX 1003.1-2001 标准的系统上,传统的选项语法中的前导 '-' 可以用具有相同含义的 '+' 代替,并且在存在于 POSIX 1003.1-2001 之前的过时系统上,当两者冲突时,传统用法会覆盖正常用法。可以使用 _POSIX2_VERSION 环境变量来控制此行为(参见标准符合性)。
为了在标准主机上使用的脚本应避免传统语法,并应使用 -c num[b]、-n num 和/或 -f。如果您的脚本还必须在仅支持传统语法的主机上运行,通常可以重写它以避免问题用法,例如使用 'sed -n '$p 而不是 'tail -1'。如果不能这样做,脚本可以使用类似 'if tail -c +1 </dev/null >/dev/null 2>&1; then …' 的测试来决定使用哪种语法。
即使您的脚本假设标准行为,您仍应注意那些根据 POSIX 版本而有不同行为的用法。例如,避免 'tail - main.c',因为它可能被解释为 'tail main.c' 或 'tail -- - main.c';避免 'tail -c 4',因为它可能意味着 'tail -c4' 或 'tail -c 10 4';避免 'tail +4',因为它可能意味着 'tail ./+4' 或 'tail -n +4'。