head 与 tail 实战:取头取尾、取中间段与 tail -F 轮转坑
tail -f 盯着日志排查问题,半夜日志明明还在滚,屏幕却突然静止不动了——日志没停,是 tail -f 被日志轮转甩掉了。这是这对”最简单的命令”里藏得最深的坑,放在最后讲;先把 head 和 tail 本身理顺。
这是 Linux 命令系列的一篇,承接 Linux 常见命令与工具地图。head 输出文件(或管道输入)的开头部分,tail 输出结尾部分,默认都是 10 行——两个天生一对的小工具,和 cut/sort/uniq 那批 一样,真正的威力在管道组合里。
head:取开头
1 | head /var/log/app.log |
tail:取结尾,和一个特殊语法
1 | tail /var/log/app.log |
-n +N 这个加号语法容易被忽略:tail -n 5 是”最后 5 行”,tail -n +5 是”从第 5 行到结尾”——一个从后往前数,一个从前往后跳,方向完全相反。
head + tail 组合:取中间任意一段
两个命令一接,就能精确取出文件中间的任意行段:
1 | head -n 12 access.log | tail -n 5 |
典型场景:报错信息在日志第 3800 行附近,head -n 3820 app.log | tail -n 40 直接把上下文捞出来,不用打开几十万行的大文件翻。
tail -f:实时跟踪日志
1 | tail -f /var/log/app.log |
tail -F:日志轮转的正解
回到开头的问题。tail -f 打开文件后,盯住的是打开那一刻的文件本体(准确说是它的 inode,这个概念在 ln 那篇 讲过)。而日志轮转(logrotate)的动作通常是:把 app.log 改名成 app.log.1,再新建一个空的 app.log 继续写。
于是 -f 的困境出现了:它还忠实地盯着旧 inode——也就是改名后的 app.log.1,那个文件再也不会有新内容了,屏幕自然一片死寂;新日志全写进了新建的 app.log,没人看。
-F 就是为这个场景设计的:
1 | tail -F /var/log/app.log |
结论很简单:只要盯的日志会轮转(生产环境的日志几乎都会),一律用大写 F。多敲一个大写字母,省掉半夜”日志为什么不动了”的惊魂。
常用参数速查表
| 命令/参数 | 作用 |
|---|---|
head 文件 / tail 文件 |
取开头 / 结尾,默认各 10 行 |
head -n N / tail -n N |
指定行数 |
head -c N |
按字节取开头 N 字节 |
tail -n +N |
从第 N 行取到结尾(+2 跳过表头) |
head -n N | tail -n K |
取第 N-K+1 到第 N 行的中间段 |
tail -f |
实时跟踪新增内容 |
tail -f | grep --line-buffered |
实时过滤,避免 grep 缓冲攒批 |
tail -F |
跟踪且自动处理日志轮转,生产日志一律用它 |
写到这里
head/tail 五分钟就能全部学完,值得刻进记忆的是三个点:-n +N 的加号语义(从第 N 行到结尾)、head | tail 取中间段的组合、以及 -F 对 -f 的完全上位替代(只要日志会轮转)。最后这个坑踩过一次就再也忘不掉——不如直接从今天开始把 -F 设成肌肉记忆。









