Linux Grep 命令终极指南:从基础搜索到正则高阶实战
在 Linux 系统运维、日志分析和代码检索中,grep(Global Regular Expression Print)无疑是最高频使用的工具之一。它不仅能快速定位文本,配合正则表达式更能实现复杂的模式匹配。
本文将带你从基础用法进阶到正则高阶技巧,通过实战案例掌握 grep 的核心能力。
📋 目录
1. 基础搜索与统计
最基础的用法是查找包含特定字符串的行,但 grep 的强大之处在于它能同时提供位置信息和统计数据。
🔍 显示行号 (-n)
当你在几千行的日志或代码中查找内容时,知道关键字在第几行至关重要。
# 显示 '1987-10-10' 所在的行号及内容
grep -n '1987-10-10' 2.txt
输出示例: 45:1987-10-10 Event started (表示在第 45 行)
📊 统计匹配次数 (-c)
如果你只关心某个错误出现了多少次,而不需要看具体内容,使用 -c (count)。
# 统计包含 '1987' 的行数
grep -c '1987' 2.txt
注意: 它统计的是包含匹配项的行数,而不是匹配项出现的总次数(若一行出现多次,仍计为 1)。如需统计总次数,需结合 grep -o 和 wc -l。
2. 上下文关联:还原现场
在分析日志报错时,单看报错行往往不够,我们需要查看报错前发生了什么,或者后续产生了什么影响。
| -A n | After: 显示匹配行及其后 n 行 | 查看报错后的堆栈跟踪 |
| -B n | Before: 显示匹配行及其前 n 行 | 查看报错前的用户操作记录 |
| -C n | Context: 显示匹配行及其前后各 n 行 | 全面还原事件现场 |
实战演示:
# 显示 '1987-10-10' 及其后面 2 行
grep -A 2 '1987-10-10' 2.txt
# 显示 '1987-10-10' 及其前面 2 行
grep -B 2 '1987-10-10' 2.txt
# 显示 '1987-10-10' 及其前后各 2 行 (最常用)
grep -C 2 '1987-10-10' 2.txt
3. 文件级操作:批量筛选
当面对成百上千个日志文件时,我们往往不需要看具体内容,只需要知道哪些文件包含了目标关键字。
📁 列出包含关键字的文件 (-l)
# 列出当前目录下所有包含 'exception' 的 .log 文件
grep -l 'exception' *.log
用途: 快速定位问题文件,配合 vim 或 cat 进一步查看。
🚫 列出不包含关键字的文件 (-L)
# 列出所有不包含 '孙' 的 .txt 文件
grep -L '孙' *.txt
用途: 排除法,例如找出尚未处理过的配置文件。
🔤 忽略大小写 (-i)
日志中的关键词大小写可能不统一(如 Error, error, ERROR),使用 -i 可一网打尽。
# 不区分大小写搜索复杂的类名
grep -i 'DiscoveryClient-InstanceInfoReplicator-0' apollo-assembly.log
4. 正则表达式核心实战
grep 的灵魂在于正则表达式(Regular Expression)。默认情况下,grep 使用基本正则表达式 (BRE)。
📍 锚点匹配:行首与行尾
- ^ : 匹配行的开始。
- $ : 匹配行的结束。
# 匹配以 '1993-01' 开头的行 (常用于按月份筛选日志)
grep '^1993-01' 2.txt
# 匹配以 '17' 结尾的行
grep '17$' 2.txt
# 精确匹配:整行内容必须完全是 "a.e" (点号在正则中通常代表任意字符,但在某些语境需转义,此处演示精确行匹配逻辑)
# 注意:若需匹配字面意义的点,应写作 grep "^a\\.e$"
grep "^a.e$" data.txt
🔁 反向引用:匹配连续重复字符
这是一个高阶技巧,用于查找拼写错误(如 helloo)或特定格式。 $.\\$\\1 的含义:
# 匹配包含连续两个相同字母的单词 (如 "book", "see", "error")
grep '$.$\\1' data.txt
🎯 单词边界匹配 (-w 或 \\< \\>)
避免“误伤”。例如搜索 status 时,不想匹配到 registration status 中的 status 以外的部分,或者不想匹配到 statuses。
方法一:使用 -w 选项 (推荐)
# 仅匹配完整的单词 'registration status' (作为独立单词存在)
grep -w –color 'registration status' apollo-assembly.log
方法二:使用正则符号 \\< 和 \\>
# \\< 表示单词开始,\\> 表示单词结束
grep –color '\\<registration status\\>' apollo-assembly.log
提示: –color 参数会让匹配到的关键字高亮显示,便于肉眼识别。
5. 递归搜索与文件过滤
在大型项目中,我们需要递归遍历子目录,并且只关注特定类型的文件(如只看 .java 或 .js,忽略编译产生的 .class 或二进制文件)。
🌲 递归搜索 (-r / -R)
# 递归搜索当前目录及子目录
grep -r 'keyword' ./
🧹 配合 –include 精准过滤
这是开发中最常用的组合,避免在无关文件中浪费时间和产生噪音。
# 1. 列出所有 .js 文件路径 (不显示内容,只显示文件名 -l)
grep -rl –include="*.js" ./
# 2. 同时搜索 .js 和 .java 文件
grep -r –include="*.js" –include="*.java" "NullPointerException" ./
# 3. 使用大括号扩展匹配多种后缀 (注意:部分 shell 需开启 extglob,或在 grep 中直接写多个 include 更稳妥)
# 下面这种写法在某些 grep 版本可能不支持大括号展开,建议拆分为多个 –include
grep -rl –include="*.java" –include="*.vue" "re" .
6. 高阶技巧:提取异常堆栈
在 Java 等语言的日志中,一个 Exception 往往伴随多行堆栈信息(以 at … 开头)。普通的 grep 只能打印包含 “Exception” 的那一行,丢失了关键的堆栈上下文。
我们可以利用 Perl 兼容正则 (-P) 和 空字节分隔 (-z) 来实现多行块匹配。
🛠️ 提取 Exception 及其堆栈
grep –binary-files=text -Pzo '(?s)Exception[^\\n]*\\n(?:\\s+at[^\\n]*\\n)*' info.log
命令深度解析:
- –binary-files=text: 强制将文件当作文本处理,避免遇到二进制字符时报错 “Binary file matches”。
- -P: 启用 Perl 兼容正则表达式 (PCRE),支持更强大的语法。
- -z: 将输入视为由 null 字符分隔的数据流(实际上让 grep 把整个文件当作一行处理),从而允许跨行匹配。
- -o: 只输出匹配到的部分。
- 正则逻辑 (?s)Exception[^\\n]*\\n(?:\\s+at[^\\n]*\\n)*:
- (?s): 开启单行模式,让 . 能匹配换行符(虽然这里主要用 [^\\n])。
- Exception[^\\n]*\\n: 匹配包含 “Exception” 的那一行。
- (?:\\s+at[^\\n]*\\n)*: 非捕获组,匹配后续所有以空白字符开头且包含 “at” 的行(即堆栈行),* 表示匹配 0 次或多次,直到遇到非堆栈行。
注意: 此命令输出的结果末尾可能会有一个空字符(null byte),在终端显示时可能表现为 % 或换行异常,可通过管道 | tr '\\0' '\\n' 进行美化。
💡 总结与建议
| 查错别字/定位代码 | grep -n |
| 分析日志上下文 | grep -C 5 |
| 统计错误频率 | grep -c |
| 查找特定类型文件 | grep -r –include="*.java" |
| 提取完整报错堆栈 | grep -Pzo … |
最佳实践提示:
掌握这些技巧,你将能像手术刀一样精准地剖析任何文本数据!



