4、日志过滤与搜索:grep高级用法、awk基础、sed基础

日志排查,说白了就是在一堆乱麻里找线头。我干了这么多年运维,最怕的不是日志多,而是不知道怎么快速找到想要的东西。今天咱们就聊聊三个最趁手的工具:grep、awk 和 sed。掌握了它们,你排查问题的速度至少能快三倍。

4.1 grep 高级用法:不只是搜个关键字

很多人用 grep 还停留在 grep "error" app.log 这种水平。说实话,这只能算入门。真正的高手,会用 grep 玩出花来。

4.1.1 正则匹配:精准定位

正则表达式是 grep 的灵魂。我个人习惯,遇到复杂日志先用正则把范围缩小。

常见场景:匹配 IP 地址

# 匹配所有 IPv4 地址
grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' access.log

# 匹配以 192.168 开头的内网 IP
grep -E '^192\.168\.' access.log

匹配时间戳范围

# 匹配 2024-01-15 10:00:00 到 10:59:59 之间的日志
grep -E '2024-01-15 10:[0-5][0-9]:[0-5][0-9]' app.log
我的经验:用 -E 参数启用扩展正则,比默认的基本正则好用得多。我在项目中遇到过很多次,因为正则写得太复杂导致性能问题。记住一个原则:能用简单字符串匹配的,就别上正则。

4.1.2 上下文显示:看前后文才完整

光匹配到一行错误有什么用?你得看看它前后发生了什么。grep 提供了三个参数:

参数 含义 示例
-A n 显示匹配行及之后 n 行 grep -A 5 "ERROR" app.log
-B n 显示匹配行及之前 n 行 grep -B 5 "ERROR" app.log
-C n 显示匹配行及前后各 n 行 grep -C 5 "ERROR" app.log

实战案例:排查 OOM 错误

# 查看 OutOfMemoryError 前后各 10 行
grep -C 10 "OutOfMemoryError" catalina.out

# 只看错误发生前的 20 行(看是什么操作导致的)
grep -B 20 "OutOfMemoryError" catalina.out
注意:我曾经在分析一个 2GB 的日志文件时,直接用 -C 100 查看上下文,结果终端卡死了。建议上下文行数控制在 20 行以内,除非你确定文件不大。

4.1.3 递归搜索:翻遍整个目录

有时候错误日志分散在多个子目录里,一个个找太傻了。用 -r 参数:

# 递归搜索 /var/log 下所有包含 "Connection refused" 的文件
grep -r "Connection refused" /var/log/

# 只搜索 .log 文件,忽略二进制文件
grep -r --include="*.log" "Connection refused" /var/log/

# 排除某些目录(比如排除 archive 目录)
grep -r --exclude-dir="archive" "Connection refused" /var/log/

我的避坑指南:我曾经在排查问题时,用 grep -r "error" / 搜索整个根目录,结果把系统搞卡了。记住:递归搜索一定要限定目录范围,或者加上 --max-depth 限制深度。

4.2 awk 基础:结构化处理日志

grep 只能帮你找到行,但 awk 能帮你把行拆成字段来分析。说白了,awk 就是日志界的 Excel。

4.2.1 基本用法:按列提取

awk 默认按空格或制表符分割字段。$1 表示第一列,$2 表示第二列,$0 表示整行。

# 查看 access.log 的 IP 和状态码(第1列和第9列)
awk '{print $1, $9}' access.log

# 只显示 500 错误的请求
awk '$9 == 500 {print $1, $7, $9}' access.log

4.2.2 指定分隔符

很多日志不是空格分隔的,比如 CSV 或自定义格式。用 -F 指定分隔符:

# 处理以逗号分隔的日志
awk -F',' '{print $1, $3}' data.csv

# 处理以竖线分隔的日志
awk -F'|' '{print $2, $5}' app.log

4.2.3 统计与聚合

awk 还能做简单的统计,这个在排查问题时特别有用。

# 统计每个 IP 的访问次数
awk '{count[$1]++} END {for (ip in count) print ip, count[ip]}' access.log

# 统计每个状态码的出现次数
awk '{count[$9]++} END {for (code in count) print code, count[code]}' access.log

# 计算平均响应时间(假设第10列是响应时间)
awk '{sum+=$10; count++} END {print "平均响应时间:", sum/count, "ms"}' access.log

我的经验:有一次线上告警说接口响应慢,我用 awk 统计了每个接口的平均响应时间,发现某个接口的平均值高达 5 秒。再结合 grep 看那个接口的日志,发现是数据库连接池满了。你看,awk 和 grep 配合起来,排查效率翻倍。

4.3 sed 基础:流式编辑日志

sed 是流编辑器,适合对日志进行批量替换、删除、插入操作。我一般用它来清洗日志数据。

4.3.1 替换操作

# 将所有的 "ERROR" 替换为 "错误"
sed 's/ERROR/错误/g' app.log

# 只替换每行第一次出现的 "ERROR"
sed 's/ERROR/错误/' app.log

# 替换并保存到原文件(-i 参数)
sed -i 's/旧IP/新IP/g' config.conf

4.3.2 删除操作

# 删除所有空行
sed '/^$/d' app.log

# 删除包含 "DEBUG" 的行(排除调试日志)
sed '/DEBUG/d' app.log

# 删除第 10 到第 20 行
sed '10,20d' app.log

4.3.3 实战:日志脱敏

我在项目中遇到过需要把日志里的敏感信息(如手机号、身份证号)脱敏后再发给第三方分析。sed 可以轻松搞定:

# 手机号脱敏:138****1234
sed -E 's/(1[3-9][0-9])[0-9]{4}([0-9]{4})/\1****\2/g' app.log

# IP 地址脱敏:192.168.*.*
sed -E 's/([0-9]{1,3}\.[0-9]{1,3})\.[0-9]{1,3}\.[0-9]{1,3}/\1.*.*/g' app.log

注意:sed 的 -i 参数会直接修改原文件。我建议先用不带 -i 的命令预览结果,确认无误后再加 -i。我曾经手滑把配置文件改坏了,还好有备份。

4.4 三剑客配合:实战案例

单独用每个工具都能干活,但配合起来才是王道。我给你画个图,看看它们的分工:

日志排查三剑客分工图 原始日志文件 grep 过滤 & 搜索 正则匹配、上下文 awk 结构化处理 字段提取、统计 sed 流式编辑 替换、删除、脱敏 排查结果 统计报表 清洗后数据 grep 找线索 → awk 做分析 → sed 做清洗,三步搞定日志排查

实战:找出访问量最高的 IP 并统计

# 第一步:grep 过滤出 500 错误的请求
# 第二步:awk 提取 IP 并统计次数
# 第三步:sort 排序,取前 10
grep " 500 " access.log | awk '{count[$1]++} END {for (ip in count) print count[ip], ip}' | sort -rn | head -10

实战:清洗日志中的敏感信息并统计错误类型

# 先脱敏,再统计
sed -E 's/(1[3-9][0-9])[0-9]{4}([0-9]{4})/\1****\2/g' app.log | \
  grep -E "ERROR|FATAL" | \
  awk -F'[][]' '{print $2}' | \
  sort | uniq -c | sort -rn

我的总结:这三个工具就像运维的三把刀。grep 是手术刀,精准定位;awk 是解剖刀,拆解分析;sed 是打磨刀,修整清洗。你想想看,如果只会其中一个,排查问题的效率至少打五折。我建议你平时多练练管道组合,把三个工具串起来用,这才是真正的日志排查高手。

嗯,今天就聊到这儿。记住:日志排查不是靠蛮力,而是靠巧劲。用好这三个工具,你也能在日志的海洋里游刃有余。