当前位置:首页>Linux>每天学一个Linux命令系列(8):cat/less/tail - 看文件别只用cat了

每天学一个Linux命令系列(8):cat/less/tail - 看文件别只用cat了

  • 2026-10-11 06:00:07
每天学一个Linux命令系列(8):cat/less/tail - 看文件别只用cat了
运
运维少年 · 科技观察

这个命令是干啥的

这三个命令都是看文件内容的,但场景完全不同:

  • ·cat:适合小文件,一次性全部输出到终端
  • ·less:适合大文件,分页浏览,支持搜索和导航
  • ·tail:适合看文件末尾,特别是实时跟踪日志

刚学 Linux 的时候我只会 cat,看啥都用 cat。大日志文件直接刷屏,日志实时跟踪更是无从下手。后来分清了这三个命令的使用场景,效率提升了一大截。

基本用法(3分钟上手)

cat 基础

# 看文件内容
cat file.txt

# 合并多个文件
cat file1.txt file2.txt > merged.txt

# 显示行号
cat -n file.txt

# 显示不可见字符(制表符、换行符)
cat -A file.txt

-A 会把制表符显示成 ^I,行尾显示 $。排查配置文件的空格和制表符混用时特别好用。

less 基础

# 分页查看
less file.txt

# 翻页和搜索
# 按 j/k 或 上/下 箭头:逐行滚动
# 按 空格键:下一页
# 按 b:上一页
# 按 / 后输入关键词:搜索
# 按 n:下一个匹配
# 按 N:上一个匹配
# 按 g:跳转到文件开头
# 按 G:跳转到文件末尾
# 按 q:退出

tail 基础

# 查看文件末尾10行
tail file.txt

# 查看末尾50行
tail -n 50 file.txt

# 实时跟踪文件新增内容
tail -f app.log

tail -f 是我每天用最多的命令。查线上问题的时候,开个终端跑 tail -f error.log,触发操作后马上就能看到日志。

进阶骚操作

1. cat 的骚操作

清空文件而不删除文件本身:

# 用重定向清空文件
> file.txt

# 或者用 /dev/null 清空
cat /dev/null > file.txt

这两种方式都只清空文件内容,文件依然存在,权限属性不变。如果你有程序在写这个文件(比如 Nginx 日志),清空后程序可以继续往里面写。如果你 rm 再 touch,新文件 inode 变了,程序可能就懵了。

创建文件并写内容:

# 创建文件并写入内容,Ctrl+D 结束
cat > newfile.txt << EOF
这是内容
多行内容
EOF

合并文件时加分隔符:

# 在合并文件间插入文件名作为分隔
for f in *.txt; do
    echo "===== $f ====="
    cat "$f"
done > all_merged.txt

2. less 的骚操作

less 实时跟踪:

# less 模式下按 F:进入跟踪模式(类似 tail -f)
# Ctrl+C 退出跟踪模式回到 less 页面
less +F app.log

这个用法很多人不知道。我在排查线上问题时,先用 less 打开日志文件搜索关键错误,然后按 F 开始实时跟踪,看到更多错误后再按 Ctrl+C 切换回浏览模式,继续搜索。一个 less 搞定所有操作。

less 打开文件到指定行或位置:

# 打开文件直接到第100行
less +100 file.txt

# 打开文件直接到第一次出现 "ERROR" 的位置
less +/ERROR app.log

# 显示行号
less -N file.txt

less 标记书签:

# 在 less 中按 m 后跟一个字母(比如 a):标记当前位置
# 按 ' 后跟同一个字母:跳转回标记位置

看长配置文件时,用 m 标记几个关键位置,来回切换很方便。

less 查看压缩文件:

less app.log.gz  # 直接看,不需要先 gunzip

less 内置了 zlib 支持,能直接查看 gzip 压缩的文本文件。这个我经常用,服务器上老的日志文件都压缩了,less 直接打开,不用解压。

3. tail 的骚操作

-f 和 -F 的区别:

# 跟踪文件,但如果文件被删除/重命名,就停了
tail -f app.log

# 跟踪文件,如果文件被删除/重命名,会尝试重新打开
tail -F app.log

tail -f 跟踪的是文件描述符(inode)。如果日志轮转脚本把 app.log 重命名成 app.log.1 然后创建新的 app.log,tail -f 还是盯着旧的 app.log.1 不放,新日志你看不到。tail -F 检测到文件被替换后会重新打开,我经历过好几次因为没用 -F 而漏看日志的尴尬。

同时跟踪多个文件:

# 同时跟踪多个日志文件
tail -F /var/log/nginx/access.log /var/log/nginx/error.log

# 输出会带上文件名标签
# ==> /var/log/nginx/access.log <==
# 192.168.1.1 - - [22/Jun/2024:10:00:00 +0800] ...
# ==> /var/log/nginx/error.log <==
# 2024/06/22 10:00:01 [error] ...

线上排查问题时我经常开一个终端窗口,同时跟踪多个相关服务的日志,一眼就能看到上下游的调用顺序。

从指定行开始看:

# 从第1000行开始看
tail -n +1000 largefile.log

+1000 表示从第 1000 行开始。这个参数配合 head 或者 less 可以分段查看大文件。

避坑指南

坑1:cat 看二进制文件

# 终端直接乱码,甚至卡死
cat binary_file.bin

二进制文件打到终端上,终端会尝试解析不可打印字符,可能触发转义序列,轻则乱码,重则终端卡死。如果确认是二进制文件,用 hexdump、od 或者 xxd。

坑2:cat 大文件刷屏

# 几个G的日志文件,直接刷到眼睛瞎
cat hugefile.log

终端滚动几十万行,查个东西得翻半天。大文件用 less,日志实时用 tail -f,cat 只适合看一眼小文件。

坑3:管道里用 cat 多此一举

# 新手写法
cat file.txt | grep "error"  # cat 完全多余

# 正确写法
grep "error" file.txt

猫管道(useless use of cat)是新手常见问题。很多命令可以直接接受文件名参数,不需要 cat 再管道。

坑4:tail -f 不会自动退出

# 这个命令会一直卡住
tail -f app.log

tail -f 是阻塞的,按 Ctrl+C 退出。SSH 会话断了的话进程也会断。需要后台运行的话用 nohup 或者 tmux。另外 tail -f 在日志文件被删除后可能一直卡着不输出,用 -F 替代。

坑5:less 搜索大小写

less 默认搜索是大小写敏感的。less -i 可以忽略大小写,或者搜索时用 /error 然后按 -i 切换。

实战场景(重点!结合真实运维场景)

场景1:排查线上错误

应用突然报错了,快速排查流程:

#!/bin/bash
# 快速定位问题工具

LOG_DIR="/var/log/myapp"

echo "=== 1. 最近10分钟的错误 ==="
# 实时跟踪错误日志,匹配最近10分钟的ERROR
tail -n 5000 "${LOG_DIR}/app.log" | grep "ERROR" | tail -20

echo "=== 2. 错误出现频率 ==="
# 统计ERROR类型分布
grep "ERROR" "${LOG_DIR}/app.log" | awk '{print $NF}' | sort | uniq -c | sort -rn | head -5

echo "=== 3. 观看实时日志 ==="
echo "按 Ctrl+C 退出跟踪"
# 使用 -F 避免日志轮转后跟丢
tail -F "${LOG_DIR}/app.log"

我线上排查问题的标准流程:先用 grep 捞历史日志里的 ERROR,然后 tail -F 实时盯住新的错误输出。一个终端搞定排查。

场景2:分析 Nginx 访问日志

#!/bin/bash
# 实时监控 Nginx 访问情况

NGINX_LOG="/var/log/nginx/access.log"

echo "实时 IP 访问排行(10秒更新)"
# 每10秒统计一次最近的IP访问排行
while true; do
    clear
    echo "=== 当前访问最多的 IP(最近1000条) ==="
    tail -1000 "$NGINX_LOG" | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
    echo ""
    echo "=== 当前请求最多的 URL(最近1000条) ==="
    tail -1000 "$NGINX_LOG" | awk '{print $7}' | sort | uniq -c | sort -rn | head -10
    sleep 10
done

这个脚本帮我发现过几次异常的爬虫行为。某个 IP 突然冲到第一,查一下 User-Agent 就能判断是正常爬虫还是恶意扫描。

场景3:日志分析的黄金组合

#!/bin/bash
# 分析昨天全天的日志

LOG_FILE="/var/log/myapp/app.$(date -d 'yesterday' +%Y%m%d).log"

echo "=== 昨天日志统计 ==="

# 总行数
TOTAL=$(wc -l < "$LOG_FILE")
echo "总请求量:$TOTAL"

# ERROR 数量
ERRORS=$(grep -c "ERROR" "$LOG_FILE")
echo "ERROR 数量:$ERRORS"
echo "错误率:$(echo "scale=2; $ERRORS * 100 / $TOTAL" | bc)%"

# 最频繁的错误类型
echo "=== 前10个最常见错误 ==="
grep "ERROR" "$LOG_FILE" | sed 's/.*ERROR //' | sort | uniq -c | sort -rn | head -10

这条命令是我每天的例行检查。如果错误率超过 1%,我会进一步用 less 打开日志文件,搜索具体的时间段和相关上下文。

今日作业

线上有一个持续写入的日志文件 /var/log/myapp/app.log,需要用一条命令实现以下效果:

1. 实时跟踪日志(日志轮转后依然能跟住)
2. 只显示包含 "ERROR" 或 "WARN" 的行
3. 同时跟踪该目录下的 error.log

写出来这条命令。

(提示:组合 tail -F 和 grep,多文件用通配符或者多个文件参数。)

E N D

运维少年 · 科技观察

最新文章

随机文章