
前言
在一次日常工作中,我发现一位新同事在排查测试环境的问题时,日志查询效率非常低。
当应用报错,钉钉机器人推送了告警信息后,他的排查流程是这样的:首先尝试使用 tail -f 命令配合 grep 等待异常出现,但这种方式只能捕获单行错误信息,无法获取完整的异常堆栈。随后,他改用 vi 编辑器打开庞大的日志文件,通过手动搜索关键词并逐个跳转来定位问题,整个过程耗时且容易遗漏关键上下文。
这种低效的排查方式在紧急的线上问题面前无疑是致命的。因此,我决定系统地分享一套基于 grep 命令的高效日志排查方法,旨在通过几个核心场景的实战演示,快速提升定位问题的能力。
正式教学
grep 是 Linux 环境下最强大的文本搜索工具之一,熟练掌握其参数组合能极大提升日志分析效率。下面将针对不同排查场景,介绍具体的命令用法。
场景一:如何获取完整的异常堆栈信息
Java 应用程序抛出的异常通常包含多行堆栈信息,仅搜索异常名称(如 NullPointerException)只能看到首行,无法定位根本原因。
解决方案:使用 grep 的 -A (After) 参数,显示匹配行之后的若干行内容。
# 查找 NullPointerException,并显示其后 50 行内容
grep -A 50 "java.lang.NullPointerException" a.log
如果搜索结果较多,可以结合 less 命令进行分页查看,便于浏览:
grep -A 50 "java.lang.NullPointerException" a.log | less
在 less 视图中,你可以:
- 使用 方向键 或 Page Up/Page Down 翻页。
- 输入
G 直接跳转到文件末尾。
- 输入
/ 后跟关键词(如 /Exception)进行二次搜索。
- 按
q 键退出。

场景二:实时监控并捕获新产生的异常日志
当需要监控正在运行的应用,并希望在其抛出异常时立即获知详情,可以将 tail -f 与 grep 结合使用。
# 实时跟踪 a.log 文件的新增内容,并过滤出包含指定异常及其后续堆栈的行
tail -f a.log | grep -A 50 "java.lang.NullPointerException"
执行此命令后,终端将处于监控状态。一旦有匹配的异常日志产生,其完整堆栈信息便会自动打印出来。
- 按
Ctrl + C 可终止监控。
- 可添加
-i 参数进行不区分大小写的搜索,避免因大小写不一致而遗漏。
场景三:搜索历史日志文件或压缩日志
生产环境的日志通常会按日期或大小进行切割和归档,可能以 .log.2025-07-02 或 .log.2025-07-02.gz 的形式存在。
搜索多个普通日志文件:
使用 -H 参数可以在输出中显示匹配项所在的文件名,这对于在多文件中定位问题来源非常关键。
# 搜索当前目录下所有 .log 文件
grep -H -A 50 "java.lang.NullPointerException" *.log
搜索压缩的 .gz 日志文件:
无需手动解压,直接使用 zgrep 命令,其参数与 grep 完全一致。
# 搜索当前目录下所有 .gz 压缩包内的日志
zgrep -H -A 50 "java.lang.NullPointerException" *.gz
场景四:统计异常出现频率
评估某个异常是偶发现象还是频发问题,可以使用 -c (count) 参数进行快速统计。
# 统计单个文件中异常出现的次数
grep -c "java.lang.NullPointerException" a.log
# 统计多个文件中异常出现的总次数
grep -c "java.lang.NullPointerException" *.log
其他常用 grep 参数速查
| 参数 |
作用描述 |
-B N |
显示匹配行之前的 N 行 (Before) |
-A N |
显示匹配行之后的 N 行 (After) |
-C N |
显示匹配行上下各 N 行 (Context) |
-i |
忽略大小写进行匹配 |
-H |
输出时显示文件名 |
-r |
递归搜索指定目录下的所有文件 |
例如,使用 -C 参数可以同时查看异常发生前后的日志上下文,这对于分析异常触发前的业务逻辑流很有帮助:
grep -C 25 "java.lang.NullPointerException" a.log
总结
本文介绍了几种基于 grep 命令的高效日志排查场景化方法,涵盖了获取完整堆栈、实时监控、搜索历史及压缩文件、统计频率等核心需求。熟练掌握这些 Shell 脚本技巧,是每一位后端开发者及运维人员的基本功,能显著提升线上问题排查的效率与准确性。实际上,awk、sed、wc 等命令同样在日志分析中扮演着重要角色,它们与 grep 的组合使用能解决更复杂的数据处理问题。