Linux tail 命令:查看文件末尾与实时跟随日志
tail 用于查看文件末尾;不加选项时默认输出最后 10 行。用 -n 指定行数,用 -f 持续查看追加内容;在 GNU tail 中,文件因日志轮转被替换时,可考虑 -F 按文件名重新打开并重试。
排查故障时,可以先看最近的日志,再决定是否持续跟踪。以下说明行数与字节范围、轮转、过滤、多个文件以及权限问题。示例中的日志路径和文件名需要替换为实际存在、且自己有权读取的文件。
tail 是什么?
tail 输出输入数据的末尾部分。没有指定文件,或文件参数为 - 时,它读取标准输入;默认按行处理,显示末尾 10 行。文件不足 10 行时,输出已有内容。
它适合查看大型日志的尾部,不负责保存日志、识别故障原因或建立历史索引。持续跟踪只反映能从输入读取到的内容,不能代替日志收集和归档。
基本语法与用法
下列语法中的方括号表示可选项,options 和 file... 是占位说明,不应原样输入:
tail [options] [file...]
查看 /var/log/app.log 的最后 10 行:
tail /var/log/app.log
需要最后 20 行时,指定 -n 20:
tail -n 20 /var/log/app.log
某些实现也支持 -20 这样的旧式简写,但脚本和文档中使用明确的 -n 20 更易理解。文件不存在会报错;不要将路径示例误认为每台 Linux 都自带的日志文件。
如何输出指定范围?
最后 N 行
-n N 从文件末尾取出最多 N 行。例如,查看最近 50 行访问记录:
tail -n 50 access.log
需要分页阅读较长输出时,可以通过管道交给 less:
tail -n 500 access.log | less
在 less 中上下移动阅读,按 q 退出。这里的管道只传递末尾 500 行,不是把整个原文件交给分页器。
从第 N 行到末尾
-n +N 中的加号改变了含义:从文件开头数到第 N 行,再输出到末尾,行号从 1 开始。
tail -n +2 data.csv
对于第一行就是单行表头的 CSV,这会跳过第一行。不过 tail 按换行符处理文本,不理解 CSV 的引号和跨行字段;一行不一定等于一条 CSV 记录。
按字节输出
-c N 输出最后 N 个字节。GNU tail 支持容量后缀,例如 K 表示 1024,M 表示 1024²;kB 则表示 1000 字节:
tail -c 1K output.bin
这个例子最多输出最后 1024 字节,不是 1024 个字符。二进制数据可能含终端控制字节,实际检查时宜重定向到文件或交给适合的查看工具。-c +N 表示从第 N 字节开始;按字节截取可能切断 UTF-8 中文字符,文本通常优先按行处理。
持续查看新日志
用 -f 跟随已打开的文件
-f 先输出已有文件的末尾,再继续输出追加内容。GNU tail 默认跟随文件描述符,即程序已打开的那个文件:
tail -f /var/log/app.log
按 Ctrl+C 停止并返回 shell。这只结束读取,不删除日志,也不会停止写日志的服务。
用 -F 应对日志轮转
日志轮转(log rotation)可能将旧文件改名,再创建同名新文件。GNU -F 相当于 --follow=name --retry:按名称跟随,并在文件暂时不可访问时继续尝试打开。
tail -F /var/log/app.log
长期查看此类服务日志时,-F 往往更合适。GNU Coreutils 的 tail 官方文档源文件详细说明了两种跟随方式;本机选项仍以 tail --help 为准。
轮转方式也可能是复制后截断原文件。GNU tail 检测到文件缩小时会提示并从开头继续读取,但轮转和写入之间仍可能存在竞态;不要把终端跟踪当成保证无丢失的审计记录。
忽略已有内容,只看之后的追加
如果不需要启动时显示原有末尾 10 行,可以将行数设为 0:
tail -n 0 -f /var/log/app.log
这会跳过初始读取时已经存在的内容,随后显示追加数据。它按文件读取位置工作,不按每条日志中的时间戳筛选;若文件会被替换,可按需要将跟随方式改为 -F。
常用选项对照
| 选项 | 作用 | 示例或适用情况 |
|---|---|---|
-n N |
最后 N 行 | tail -n 100 app.log |
-n +N |
从第 N 行开始 | tail -n +2 data.csv |
-c N |
最后 N 字节 | tail -c 2K data.bin |
-f |
默认跟随文件描述符 | 同一个文件持续追加 |
-F |
按名称跟随并重试 | 改名后创建新文件的日志轮转 |
-s N |
轮询间隔为 N 秒 | tail -f -s 2 app.log;inotify 模式下通常不控制内容更新间隔 |
--pid=PID |
指定进程结束后停止跟随 | 与批处理任务日志配合,需同时跟随文件 |
-q |
不显示文件名标题 | 需要自行处理输出来源时使用 |
-v |
始终显示文件名标题 | 明确标识输出文件 |
Linux 上的 GNU、BusyBox 以及其他操作系统的 tail 并非完全相同,尤其要核对 -F 和 --pid。GNU tail 使用 inotify 时通常由文件事件触发读取;轮询模式才按睡眠间隔检查。配合 --pid 时,-s 还影响进程存活检查的频率。
日志排查的实用组合
查找最近的错误
先取最后 200 行,再查找包含 ERROR 的行:
tail -n 200 app.log | grep 'ERROR'
这只是“最后 200 行中的错误”,不是“最后 200 条错误”。grep -i 可忽略大小写;grep -n 标出的行号针对其收到的管道输入,不是原日志中的绝对行号。未匹配到内容时,grep 通常以状态 1 退出,并不等于读取失败。
持续过滤错误行
需要跟随轮转后的文件,同时仅显示匹配行时,可以使用:
tail -F app.log | grep --line-buffered 'ERROR'
GNU grep 的 --line-buffered 使用逐行输出,减少管道中的缓冲延迟,但不会消除写入程序自身的缓冲。此命令仍会先处理文件原有的末尾内容;如果只要之后的追加,可同时使用 -n 0。
这只过滤屏幕输出,不修改原日志。按 Ctrl+C 停止管道;需要复杂条件、结构化字段或长期查询时,应考虑专门的日志系统。
同时查看多个文件
指定多个文件时,tail 用文件名标题区分来源:
tail -F access.log error.log
用 -v 始终显示标题,用 -q 隐藏标题。输出按读取到的顺序交错,不会自动按日志时间戳合并排序;隐藏标题也可能丢失来源信息。
写入进程结束后退出
GNU tail 的 --pid 可在指定写入进程不再存在后结束跟随。下例的 some_command 是占位符,必须替换为实际命令;重定向 > 会覆盖已有 build.log,需选用可覆盖的新日志路径。
some_command > build.log 2>&1 &
tail --pid=$! -f build.log
$! 是当前 shell 最近启动的后台任务 ID,因此应在同一个 shell 中紧接着执行第二行,不要插入另一个后台任务。写入进程与 tail 应在同一台机器上,并具有一致可见的进程 ID;若命令派生子进程后提前退出,父进程 ID 不代表所有写入都已结束。
退出检测可能稍有延迟。tail 的退出状态也不能代替后台任务的成功与否;自动化时应及时保存该任务 ID,再用 shell 的 wait 获取实际任务退出状态,并检查日志。不要只凭跟踪结束就认定任务成功。
-f 和 -F 应该怎样选择?
| 比较项 | -f |
-F |
|---|---|---|
| 跟随依据 | 默认是已打开的文件描述符 | 指定的文件名 |
| 文件被替换 | 可能仍读取原来打开的文件 | 尝试打开同名新文件 |
| 路径暂时消失 | 不会自动改为跟随同名新文件;原描述符仍可能可读 | 通过重试等待路径重新可用 |
| 适用情况 | 观察不被替换的文件,或特意跟随旧文件 | 按名称跟随轮转日志 |
-F 并非总是更好。若写入进程在改名后继续写旧文件,-f 可能更符合观察目的。应根据服务实际写入方式和轮转策略选择,并核对路径和权限。
哪些情况应使用其他工具?
- systemd journal:日志保存在二进制 journal 中时,应使用
journalctl -f;指定服务可用journalctl -f -u service_name,并替换服务名。可参照journalctl 官方手册。 - 查看开头:使用 head 更直接。
- 在历史内容与新内容间切换:
less +F filename可进入跟随模式;按 Ctrl+C 暂停,移动阅读后按 F 恢复跟随,按q退出。具体按键以本机 less 版本为准。 - 定期重跑命令:如果要刷新的是命令结果,而不是文件追加内容,可使用英文 watch 命令说明中的方法。
- 跨服务器长期分析:需要搜索、汇总和告警时,应使用集中日志或可观测性系统。
权限与运行环境的注意事项
Permission denied
没有读取权限时会出现 Permission denied。先通过 ls -l filename 检查文件所有者和权限,也要考虑上层目录的访问权限及安全策略;根据实际职责申请必要的读取权限,避免随意扩大日志权限或给所有命令都加 sudo。
敏感日志内容
日志可能包含认证令牌、会话标识和个人信息。共享终端、复制错误消息或向外提供日志时,只取必要范围,并遮盖敏感字段。tail 不会自动匿名化或过滤秘密信息。
常见问题
tail 默认输出多少行?
默认最多输出最后 10 行。可用 tail -n 30 filename 指定其他行数;不足该行数时输出已有内容。
如何退出 tail -f?
按 Ctrl+C 停止当前跟随并返回 shell。这不会删除或修改原日志文件,也不会停止日志服务。
为什么轮转后看不到新内容?
-f 可能仍跟随旧文件。可尝试 GNU tail -F filename 按名称重新打开;仍无输出时,检查日志路径、服务写入目标、权限和缓冲情况。
能直接读取压缩日志吗?
tail 不会自动解压 gzip。可用 zcat archive.log.gz | tail -n 50 解压后取末尾,但通常仍需读取解压流前面的数据,大文件可能耗时;这也不是对压缩文件直接进行实时跟随。
使用时的要点
快速查看末尾用 tail filename,限制行数用 tail -n N filename。持续读取追加内容用 -f;文件按名称轮转时,考虑 GNU -F。结合 grep 时,要区分最近的行数、匹配结果、输出缓冲和文件来源;读取或分享日志前也应核对权限与敏感信息。




