如果你跟我一样经常在服务器上翻日志,应该体会过这种场景:应用报错只给了一个业务编号,日志文件却有好几个 G,记事本一打开就卡死,编辑器滚半天也找不到关键行。这时候能救命的往往不是可视化工具,而是命令行里那几条朴素又凶猛的 grep 命令。真正想用好 grep,光会 grep "error" app.log 远远不够,复杂日志、代码过滤、去重统计,这些场景都需要你把正则表达式揉进 grep 的参数组合里,才能做到“一把梭”。
这篇东西我不打算从 grep 的 man 手册开始念,而是直接从日志和代码两个最常见的实战场景切入,讲清楚正则怎么选、转义怎么避坑、几十 G 大文件怎么筛、以及为什么有时候你以为写对了正则却匹配不到。你可能是运维、后端、客户端开发,也可能是天天跟测试日志打交道的质量同学,只要工作里需要反复查日志、捞关键字,这篇文章都值得花十分钟看完,然后直接照着命令改。
1. grep 在日志和代码过滤里到底怎么用
1.1 从“十几个 G 的日志”说起
先讲一个真实场景。之前线上某个服务半夜报警,业务同学反馈说用户支付后没有收到回调,手里只有一个订单号类似 order-7f8a2。我登录机器,ls -lh 一看,当天日志 16GB,head -n 100 看完格式就意识到,靠 vim 根本翻不动,第一反应就是先按订单号把相关行全部扫出来:
bash复制grep -n 'order-7f8a2' app.log | grep 'ERROR'
这一步的核心思路是先粗筛再细看。第一层 grep 把所有出现这个订单号的日志行全部拉出来,第二层通过管道再筛一次,只要 ERROR 级别的记录。如果应用把 traceId、orderId 放到了日志格式的固定位置,你甚至可以写一个更精确的正则,把错误堆栈附近几十行一起带出来。
这种“管道接管道”的玩法,本质上不是 grep 有多聪明,而是它把文件流当成了可以反复过滤的水管——每次过滤都产生一个新的文本流,传给下一个命令继续处理。你只要想清楚“第一步捞什么、第二步捞什么”,复杂日志并不可怕。
1.2 从命令参数开始打好底子
想把 grep 用于复杂过滤,参数比正则本身更容易被忽略。因为很多人遇到“匹配不到”时第一反应是正则没写对,实际查下来往往是没加 -E、没加 -w,甚至没处理大文件里的隐藏字符。
下面这张参数速查表是我平时用得最频繁的,推荐你先存下来:
| 参数 | 作用 | 典型使用场景 |
|---|---|---|
-n |
显示行号 | 定位到报错行后,去编辑器或 sed 里精准跳转 |
-i |
忽略大小写 | 搜 error 时不想漏掉 Error、ERROR |
-v |
反向匹配 | 排除注释行、排除心跳日志 |
-E |
使用扩展正则 | 写分组、量词更省心,推荐默认使用 |
-P |
使用 PCRE 正则 | 需要 \d、零宽断言等高级写法时用 |
-F |
固定字符串匹配 | 匹配带大量特殊符号的内容时最稳 |
-w |
整词匹配 | 避免搜 err 时把 error 后面的字符带偏 |
-o |
只输出匹配部分 | 抽取日志中的 IP、手机号、订单号等字段 |
-c |
只输出匹配行数 | 快速统计某个级别日志数量 |
-l |
只输出文件名 | 在多个文件里找哪些文件含有关键字 |
-A/-B/-C |
输出后文/前文/上下文 | 看异常堆栈、看请求前后的日志 |
--include |
只搜指定类型文件 | grep --include='*.log' 限定日志文件 |
1.3 三个容易忽略却很实用的参数
第一个是 -F。grep 的搜索模式默认是正则,可有时候你只想找一个带大量特殊符号的字符串,比如接口路径里的 /api/v1/orders?from=app,如果原样写进单引号里,? 会被当成量词,. 会匹配任意字符,容易误伤。加个 -F 之后,grep -F '/api/v1/orders?from=app' app.log 表示纯按字面量匹配,完全绕过正则解析。甚至有一种“bash grep 不要正则匹配”的需求,说的就是这种场景,别傻乎乎把每个符号都转义,一个 -F 全部解决。
第二个是 -o。日志里经常存在“一行里有多个关键信息”的情况,比如一整行 JSON 格式日志里夹杂着 userId=U_8842 和 txnId=TXN_2025010901,如果用 grep -o,只把匹配出来的片段打印到标准输出,配合 sort、uniq -c 就能统计某类订单号出现了多少次:
bash复制grep -oE 'txnId
