Skip to content

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.csv

NR==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"
done
text
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
过滤特定行grepawk '条件'
提取特定字段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 排序 是最高频套路。脚本里把这些命令用管道串起来,能解决绝大多数文本处理问题。

下一篇讲脚本的错误处理和调试——脚本跑挂了怎么查、怎么防。