Appearance
14|文本处理实战
前面几篇学了 grep、sed、awk 各自的语法。但真实运维场景里,这些工具是组合着用的——一个问题往往要管道串起好几个工具。本篇用几个真实场景,把文本处理工具串起来用。
一、Nginx 访问日志分析
一条 Nginx access log 长这样:
text
10.0.0.5 - - [23/Jun/2026:14:30:01 +0800] "GET /api/order HTTP/1.1" 200 1234 "-" "curl/7.81"字段顺序:IP、标识、用户、时间、请求行、状态码、响应大小、来源、UA。
找访问量最高的前 10 个 IP
bash
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10拆解:awk 取第 1 列 IP → sort 排序让相同 IP 相邻 → uniq -c 去重并计数 → sort -rn 按计数降序 → head 取前 10。
这个 awk → sort → uniq -c → sort 的组合是"统计某字段出现次数"的固定套路,背下来。
找 5xx 错误最多的接口
bash
awk '$9 ~ /^5/ {print $7}' access.log | sort | uniq -c | sort -rn | head$9 ~ /^5/ 过滤状态码以 5 开头的行,$7 是请求的 URL。
统计各状态码占比
bash
awk '{count[$9]++} END {for (k in count) printf "%s: %d\n", k, count[k]}' access.log | sort用 awk 关联数组直接统计,省去 sort+uniq 组合。
找响应慢的请求
如果日志格式里有响应时间(最后一列):
bash
awk '$NF > 1 {print $7, $NF}' access.log | sort -k2 -rn | head -20$NF 取最后一列(响应时间),大于 1 秒的请求,按时间降序。
二、系统日志排查
查某时间段内的错误
journalctl 按时间过滤:
bash
journalctl --since "2026-06-23 14:00" --until "2026-06-23 15:00" | grep -i error-i 忽略大小写,error/Error/ERROR 都匹配。
提取进程名和 PID
dmesg 输出形如 [时间] 模块: 内容。只看 OOM 相关,并提取进程名:
bash
dmesg -T | grep -i "killed process" | sed -E 's/.*Killed process ([0-9]+) \(([^)]+)\).*/PID \1 进程 \2/'sed 把整行替换成格式化的输出,提取出 PID 和进程名。
三、CSV 处理
一个简单的 CSV:
text
服务,端口,状态
nginx,80,running
mysql,3306,running
redis,6379,stopped找异常的服务
bash
awk -F, 'NR>1 && $3 != "running" {print $1}' services.csv
# redis-F, 按逗号分隔,NR>1 跳过表头,$3 != "running" 过滤状态异常的,输出服务名 $1。
生成服务状态报告
bash
awk -F, '
NR==1 { next }
{ status[$3]++ }
END {
print "服务总数:", NR-1
for (k in status) printf " %s: %d\n", k, status[k]
}
' services.csvNR==1 { next } 跳过表头行。统计各状态的服务数。
四、配置文件处理
去掉注释和空行,看生效配置
bash
grep -vE '^\s*(#|$)' /etc/ssh/sshd_config-v 反向,^\s*(#|$) 匹配注释行或空行。
提取配置项的值
sshd_config 里有 Port 22。提取 Port 的值:
bash
awk '/^Port/ {print $2}' /etc/ssh/sshd_config
# 22比较两份配置的差异
bash
diff <(grep -vE '^\s*(#|$)' old.conf) <(grep -vE '^\s*(#|$)' new.conf)进程替换把两边去注释后的配置当文件传给 diff,只看实际配置的差异。
五、日志轮转后看压缩日志
logrotate 轮转后日志是 .gz 压缩的。不用解压直接看:
bash
zcat /var/log/messages.1.gz | grep error
zgrep error /var/log/messages.*.gz # 更简洁的写法zcat/zgrep/zless 都能直接处理 gzip 压缩文件。
跨多个日志文件(含压缩的)找错误:
bash
zgrep -h error /var/log/messages* | head-h 不显示文件名前缀。
六、提取和汇总
从多台机器收集磁盘使用率
bash
for host in web-01 web-02 db-01; do
ssh "$host" "df -h / | awk 'NR==2 {print \$5}'" | tr -d '\n'
echo " ← $host"
donetext
23% ← web-01
67% ← web-02
45% ← db-01注意远程命令里的 $5 要转义成 \$5,防止本地 shell 先展开。
找日志里出现最多的错误类型
bash
grep -oE 'ERROR \[[a-z]+\]' app.log | sort | uniq -c | sort -rn | head-o 只输出匹配部分,ERROR [模块名] 这种模式,统计各模块出错次数。
七、组合套路总结
| 目标 | 套路 |
|---|---|
| 统计某字段出现次数 | awk '{print $N}' | sort | uniq -c | sort -rn |
| 过滤特定行 | grep 或 awk '条件' |
| 提取特定字段 | awk '{print $N}' 或 cut -d' ' -fN |
| 改字段值 | sed 's/旧/新/' |
| 去注释空行 | grep -vE '^\s*(#|$)' |
| 看压缩日志 | zgrep/zcat |
| 多行汇总 | awk 'BEGIN{} {} END{}' |
这些套路覆盖了运维里绝大多数文本处理需求。遇到新问题先想"能不能拆成 取字段 → 过滤 → 统计 → 排序 几步",套进这个框架。
学会了之后
真实日志分析是把 grep、sed、awk、sort、uniq 组合起来用。awk 取字段 → sort 排序 → uniq -c 计数 → sort -rn 排序 是最高频套路。脚本里把这些命令用管道串起来,能解决绝大多数文本处理问题。
下一篇讲脚本的错误处理和调试——脚本跑挂了怎么查、怎么防。