这篇文章想说清楚一件事:在一堆几万行甚至几百万行的日志里,怎么用一行命令快速找到你想要的那几条。看完之后,你应该能放心地把 grep 当成排障时的第一反应,而不是第一时间打开编辑器一行一行翻。
一、面对十万行日志,你会怎么办
某天线上报警:某个服务响应变慢。
你登上服务器,打开日志文件一看,傻了——app.log 已经几十万行,里面混杂着正常请求、慢查询、偶发报错,密密麻麻的文字根本没法用眼睛扫。
这时候如果还想着用 vim 打开文件一行一行翻,基本等于在大海里找一根针。
而真正干这行的人,这时候只会敲一行命令:
grep "ERROR" app.log
一秒钟,所有包含 "ERROR" 的行全部列出来,其他几十万行噪音直接消失。
这就是 grep 存在的意义:它不是一个"高级"工具,而是排障时最基础、最高频,也最该第一时间想到的工具。
二、grep 到底是什么
grep 这个名字来自早期 Unix 编辑器 ed 里的一条命令 g/re/p,意思是"全局搜索一个正则表达式,并打印匹配的行"(global / regular expression / print)。这也是为什么 grep 天生就是为"按规则搜索文本"而设计的。
它的基本用法很简单:
grep "关键词" 文件名
意思是:在这个文件里,把所有包含"关键词"的行打印出来。
听起来简单,但排障的核心需求恰好就是这一句话——从大量文本里,把你关心的那一小部分行筛出来。grep 把这件事做到了极致:实现是用 C 写的,对纯字符串匹配做了底层优化,即使文件很大,查找速度依然很快,这也是为什么大家宁愿用一条 grep 命令,也不愿意写个脚本去逐行判断。
三、为什么排障离不开它:核心能力逐项拆解
1. 一行命令,精准定位
最基础也最常用的场景:
grep "ERROR" app.log
如果你不确定大小写,加上 -i 忽略大小写:
grep -i "error" app.log
想知道一共有多少条报错,不需要数行数,直接统计:
grep -c "ERROR" app.log
只想知道哪些日志文件里出现过报错,不需要看内容:
grep -l "ERROR" *.log
2. 上下文不丢失:-A / -B / -C
只看到报错那一行,往往看不出原因——报错前面发生了什么、报错后面服务做了什么反应,这些"上下文"信息同样重要。
grep -A 5 -B 3 "ERROR" app.log
-B 3:打印匹配行之前的 3 行(Before)- 如果前后行数一样,可以简写成
-C(Context),比如 -C 3 等价于 -A 3 -B 3
这个功能在排障里非常关键:很多时候真正的根因不在报错那一行,而在它前面几行的某个异常状态。
3. 反向过滤:把噪音排除掉
有时候你不是想找到某个关键词,而是想排除它,看看剩下的内容里还有什么。这时候用 -v(invert):
grep -v "DEBUG" app.log
意思是:把所有 DEBUG 级别的日志过滤掉,只看剩下的部分,瞬间清爽很多。
这里要提一个新手特别容易踩的经典坑:
ps aux | grep nginx
你会发现结果里除了真正的 nginx 进程,还多出一行——grep 自己也被列进去了,因为 grep 这个进程本身的启动命令里也包含 "nginx" 这个参数字符串,自然被自己匹配上了。
正确的排除方式:
ps aux | grep nginx | grep -v grep
或者更推荐的做法是,排障查进程时直接用专门为这个场景设计的 pgrep 命令:
pgrep -a nginx
这个命令不会有"匹配到自己"的问题,是更干净的替代方案。
4. 正则表达式:模糊匹配的真正威力
grep 的全名里就带着"正则表达式",这才是它真正强大的地方。
比如你想从访问日志里把所有 IP 地址提取出来:
grep -oE "([0-9]{1,3}\.){3}[0-9]{1,3}" access.log
-E:使用"扩展正则表达式"(Extended Regular Expression)
这里要补充一个技术细节:上面这个正则只是按"数字+点"的格式粗略匹配,并不会校验每一段数字是不是真的在 0-255 之间,严格来说不是一个完全准确的 IP 校验表达式,但在日常排障、快速提取场景下完全够用。
关于 -E 还要多说一句:grep 默认用的是"基本正则表达式"(BRE),像 +、?、|、{}、() 这些符号默认会被当成普通字符,必须加反斜杠转义才会生效;而加上 -E 之后用的是"扩展正则表达式"(ERE),这些符号可以直接用,不用转义。新手常见的坑就是:写了 grep "a+b" file,发现匹配不出预期结果,原因往往就是忘了加 -E,或者没意识到默认模式下 + 不是"重复"的意思。
顺带一提:egrep 这个命令历史上等价于 grep -E,fgrep 等价于 grep -F(按纯字符串匹配,不解释正则)。不过比较新的 GNU grep 已经把 egrep/fgrep 标记为过时写法,执行时会提示建议改用 grep -E / grep -F,所以现在写脚本建议直接用后者。
5. 递归搜索:一次扫完整个目录甚至整个项目
排障时经常需要的不是"某一个文件",而是"这个目录下所有日志,甚至所有子目录里的日志":
grep -rn "Connection refused" /var/log/
-n:显示匹配内容所在的行号,方便你直接定位到文件的具体位置
这个组合在排查"某个错误到底出现在哪个服务的日志里"时特别高效,不用一个个目录手动进去翻。
如果想进一步配合 find 做更精细的文件筛选(比如只搜索最近一天修改过的日志),可以这样组合:
find /var/log -name "*.log" -mtime -1 | xargs grep -l "Connection refused"
意思是:先找出最近 1 天内修改过、且文件名以 .log 结尾的文件,再把这些文件交给 grep 去搜索,最后只列出包含这个报错的文件名。
6. 配合管道,组成排障工具链
grep 很少单独使用,它真正的威力是和其他命令组合成一条"排障流水线"。几个常见组合:
tail -f app.log | grep --line-buffered "ERROR"
tail -f 持续输出日志的新增内容,grep 实时过滤出报错。这里要注意加上 --line-buffered,否则在管道场景下,grep 默认的输出缓冲机制可能导致结果不会立刻显示出来,而是攒一批之后才刷新。
journalctl -u nginx | grep -i error
在使用 systemd 的现代发行版上,很多服务的日志不再是传统的文本文件,而是由 journalctl 管理,这时候同样可以用 grep 过滤。
dmesg | grep -i "out of memory"
dmesg 输出内核日志,配合 grep 可以快速判断服务器是不是出现了内核层面的 OOM(内存溢出被杀进程)等问题。
7. 脚本里隐藏的用法:当条件判断用
很多人不知道,grep 不只是用来"看结果",它还经常被用在脚本里做条件判断。
grep 执行完之后会返回一个状态码:找到匹配返回 0,没找到返回 1,出错(比如文件不存在)返回更大的数字。配合 -q(quiet,不输出任何内容,只看状态码),可以写出这样的逻辑:
if grep -q "ERROR" app.log; thenecho"发现报错,触发告警"fi
这个用法在自动化巡检脚本里非常常见:脚本本身不需要看到具体内容,只需要知道"有没有匹配到",然后决定下一步动作。
四、还原一次真实的排障过程
把上面这些能力串起来,看看一次真实的排障大概是什么样子。
第一步:先看有多少报错,量级如何
grep -c "ERROR" app.log
发现今天报错数量明显比平时多了一个量级。
第二步:缩小时间范围
grep "2026-06-26 02:" app.log | grep "ERROR"
只看凌晨 2 点这个时间段的报错,把范围从"一整天"缩小到"一个小时"。
第三步:看报错前后的上下文
grep -B 5 -A 10 "ERROR" app.log | less
发现报错前 5 行里,有一条"数据库连接超时"的警告,初步判断根因方向。
第四步:确认这个问题是不是只发生在这台机器
grep -rl "数据库连接超时" /var/log/app/
如果发现多个服务的日志里都有这条记录,基本可以确认是数据库层面的问题,而不是某个应用实例的个例。
第五步:修复之后,验证问题是否消失
tail -f app.log | grep --line-buffered "数据库连接超时"
观察一段时间,如果再也没有匹配输出,说明问题已经解决。
整个过程,没有写一行额外的脚本,全程靠 grep 配合几个基础命令完成——这正是它被称为"排障神器"的原因:门槛极低,但能覆盖排障里最核心的"找信息"这一步。
五、新手最容易踩的几个坑
最后总结几个本文提到过、但值得单独强调一下的坑,方便你查漏补缺:
- 以为
grep 默认支持所有正则符号:实际上默认是"基本正则表达式",+、?、|、{} 等符号需要加 -E 才能直接使用,否则要手动转义。 - 用
ps aux | grep 服务名 时被自己坑:grep 进程自己也会被匹配进结果里,记得用 grep -v grep 或者直接换成 pgrep。 - 忽略大小写问题:grep 默认大小写敏感,日志里关键词大小写不统一时,记得加
-i。 - 以为
-A/-B/-C 是高级用法很少用:实际上排障时,上下文往往比报错本身更重要,这是该熟练使用的基础操作,不是可选项。 - 大文件场景下忘了限定范围:直接
grep 一个几十 GB 的日志确实能用,但如果你已经知道大概的时间范围,先用别的方式缩小范围(比如先筛选出某个时间段的日志文件),效率会更高。
写在最后
grep 从来不是一个"高级"工具,恰恰相反,它简单到几乎没有学习门槛——但正因为简单,它才能成为几乎所有 Linux 用户、不管资深还是新手,排障时下意识敲出的第一条命令。
它代表的其实是一种排障思路:先把噪音过滤掉,再去看真正重要的信息。 这个思路不只适用于 grep,也适用于你之后学的几乎所有排障工具。
你平时排障的时候,grep 最常和哪些命令搭配使用?或者你踩过哪些类似"被自己匹配进去"的坑?欢迎在评论区聊聊。