Shell 入门:用 grep、sed、awk 处理日志
服务器出问题,第一反应往往是去看日志;日志动辄几万行,靠眼睛一行行翻既慢又容易漏。Shell 里的 grep、sed、awk 正是为这种场景准备的:grep 负责“找”,sed 负责“改”,awk 负责“算”。三者配合,一条命令就能从海量日志里捞出答案。
一、grep:先把相关的行找出来
grep 是最常用的过滤工具,基本用法是 grep "关键词" 文件名。比如从应用日志里找出所有报错:
grep "ERROR" app.log
几个新手最常用的选项值得记住:-i 忽略大小写,-n 显示行号,-v 反向选择(排除匹配的行),-c 只统计行数而不是打印内容。想看报错前后的上下文,用 -A 3 显示匹配行之后 3 行,-B 3 显示之前 3 行,-C 3 则前后都显示。
grep -n -i -C 2 "timeout" app.log
grep -c "ERROR" app.log
需要跨文件查找时加上 -r,配合 --include 可以只查某一类文件:
grep -r "NullPointer" /var/log/myapp --include="*.log"
如果关键词里有空格或特殊字符,记得用引号把模式包起来;需要更复杂的模式,可以用 -E 启用扩展正则,例如匹配 ERROR 或 WARN:grep -E "ERROR|WARN" app.log。
二、sed:按规则改写文本
sed 是流编辑器,它按行读取文本、按规则处理、再输出结果,适合批量替换和删除。下面这条命令把日志里所有的 192.168.1.10 换成占位符再输出,原文件不动:
sed 's/192.168.1.10/[IP]/g' app.log
s/旧/新/g 是最常见的替换写法:s 表示替换,g 表示一行里出现多次也全部替换,不加 g 只换每行的第一个。想直接改文件要加 -i,但新手一定要先备份,或者先在不加 -i 的情况下确认输出无误再动手:
cp app.log app.log.bak
sed -i 's/DEBUG//g' app.log
sed 还能按行号操作:删除第 1 到第 10 行用 sed '1,10d' app.log,只打印第 20 到第 30 行用 sed -n '20,30p' app.log。注意 -n 和 p 要成对出现,否则会把所有行都打印一遍。
三、awk:按列拆开再统计
日志很多是按列排列的,比如 Nginx 访问日志里第 1 列是客户端 IP,第 9 列是状态码。awk 默认按空白分隔每一列,$1 是第一列,$NF 是最后一列:
awk '{print $1, $9}' access.log | head
统计访问量最高的 10 个 IP,一行命令就够:
awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -10
如果分隔符不是空白,可以用 -F 指定,例如处理逗号分隔的 CSV 日志:awk -F, '{print $2}' data.csv。awk 还自带简单的编程能力,NR 是当前行号,END 块在所有行处理完后执行,用来求和、求平均都很方便:
awk '{sum += $3} END {print "总耗时:", sum, "平均:", sum/NR}' timing.log
四、三者串起来:一次完整的排障
假设要找“今天 10 点之后,哪个接口报错最多”,可以把三个工具串成一条管道:
grep "ERROR" app.log | awk '{print $4}' | sort | uniq -c | sort -nr | head -5
这条命令先由 grep 筛出报错行,再由 awk 取出接口名那一列,最后排序计数、取前 5 名。管道的思路很简单:前一个命令的输出,就是后一个命令的输入;每一步只做一件小事,合起来就能解决复杂问题。
五、新手容易踩的坑
第一,不要写“无用的 cat”:cat app.log | grep ERROR 完全可以写成 grep ERROR app.log,少一次进程,也更清晰。第二,sed -i 改文件前先备份,改错了还能恢复。第三,在正式处理大文件前,先用 head 取前几十行在小样本上验证命令,确认结果对了再全量跑。第四,日志里可能有敏感信息,分享或截图前先脱敏,不要把真实的 IP、账号和密钥贴出去。
结语
grep、sed、awk 各自都很简单,难的是把它们组合起来用。建议从今天起,每次查日志都先想一想:能不能先 grep 缩小范围,再用 awk 按列统计,必要时用 sed 做清理?练上几次,几万行日志在你手里就只剩几行真正有用的信息了。
- 点赞
- 收藏
- 关注作者
评论(0)