grep 命令速查表 - Linux 文本搜索常用命令大全
从日志里捞报错、在仓库里找一个标识符的全部引用、判断脚本条件是否成立,都可归结为「按模式搜索行」,而 grep 的参数组合能覆盖其中九成。吃透四个就够:-r 递归、-i 忽略大小写、-C n 带上下各 n 行上下文、-E 启用扩展正则;有了它们,「找到了却不知道上下文」这个最常见的问题自然消失。多模式一组给出三条扩展路径:-e 多次指定、-f 从文件读模式、--include 与 --exclude 控制文件范围。递归一组要留意性能:在 node_modules、.git、dist 上无差别递归会慢到不可用,--exclude-dir 是必需项而非优化项。分工写在场景组里:grep 是行级筛选,awk 才是列级处理器并能做聚合,rg 默认递归且尊重 .gitignore。脚本里判断匹配用 -q 只看返回码。
典型使用场景
面向日常做日志检索与代码搜索的开发者。grep 的三个高频陷阱值得先说:默认是 BRE,`+` `?` `|` 必须转义或用 `-E`;`-o` 提取片段时不能省,否则统计会按整行算;递归搜索大目录必须用 `--exclude-dir` 排除 node_modules 与 .git,否则一次搜索能卡住几分钟。本表按基础搜索、递归、正则、上下文、多文件与常用场景六组组织,可直接当排错清单用。
基础搜索 Basic Search 7
grep "pattern" filegrep -i "pattern" filegrep -v "pattern" filegrep -c "pattern" filegrep -n "pattern" filegrep -o "pattern" filegrep -q "pattern" file递归搜索 Recursive 7
grep -r "pattern" dir/grep -R "pattern" dir/grep -rn "pattern" dir/grep -rl "pattern" dir/grep -r --include="*.log" "pattern" dir/grep -r --exclude="*.tmp" "pattern" dir/grep -r --exclude-dir="node_modules" "pattern" dir/正则表达式 Regular Expression 9
grep -E "pattern" filegrep "^start" filegrep "end$" filegrep "\<word\>" filegrep -w "word" filegrep "[0-9]" filegrep "[^0-9]" filegrep "a\|b" filegrep -E "a|b" file上下文 Context 4
grep -A 3 "pattern" filegrep -B 2 "pattern" filegrep -C 3 "pattern" filegrep -A 3 -B 2 "pattern" file多模式与文件 Multiple Patterns & Files 6
grep -e "pattern1" -e "pattern2" filegrep -f patterns.txt filegrep "pattern" file1 file2grep "pattern" *.loggrep -H "pattern" filegrep -h "pattern" file1 file2常用场景 Common Patterns 5
grep "error\|warning" app.loggrep -rn "TODO\|FIXME" src/grep -oE "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" access.loggrep -c "^$" filegrep -v "^#" file | grep -v "^$"参数矩阵
| 参数 | 作用 | 示例 |
|---|---|---|
-i / -v | 忽略大小写 / 反向排除 | grep -i "error" app.log |
-c | 统计匹配行数(不输出内容) | grep -c "^$" file |
-n / -H | 显示行号 / 显示文件名 | grep -rn "TODO" src/ |
-o | 只输出匹配片段而非整行 | grep -oE "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" access.log |
-q | 静默模式,只返回状态码(脚本用) | grep -q "ready" app.log |
-r / -R | 递归 / 递归并跟随符号链接 | grep -r "pattern" dir/ |
--include / --exclude | 限定或排除文件类型 | grep -r --include="*.log" "err" dir/ |
--exclude-dir | 排除目录,搜大项目必备 | grep -r --exclude-dir="node_modules" "x" . |
-E | 扩展正则(+ ? | 无需转义) | grep -E "a|b" file |
-w / \< \> | 匹配完整单词而非词内部 | grep -w "cat" file |
-A / -B / -C | 显示后 n 行 / 前 n 行 / 前后各 n 行 | grep -C 3 "FATAL" app.log |
-e / -f | 多个模式 / 从文件读模式 | grep -e "p1" -e "p2" file |
-l / -h | 只输出文件名 / 不输出文件名 | grep -rl "pattern" dir/ |
易错点与避坑指南
现象模式里写了 + ? | 却匹配不到。
原因grep 默认使用基本正则(BRE),这三个符号在 BRE 下是字面量。
处置加 -E 启用扩展正则,或把这些符号转义成 \+ \? \|。
现象想统计某项出现多少次,结果比实际多很多。
原因没加 -o,uniq 统计的是整行而非匹配片段。
处置加 -o 只输出匹配部分:grep -oE "模式" file | sort | uniq -c | sort -rn。
现象搜 "cat" 结果把 concatenate 也匹配出来了。
原因模式没有单词边界约束。
处置加 -w(或 BRE 下用 \<cat\>)限定为完整单词。
现象递归搜项目目录卡住,几分钟不出结果。
原因扫进了 node_modules、.git 等海量小文件目录。
处置加 --exclude-dir="node_modules" --exclude-dir=".git" 限定范围。
现象搜文件名里的点号,结果匹配到了任意字符。
原因.` 是正则元字符,字面使用未转义。
处置写成 \. 转义,或用 grep -F 按字面匹配。
现象脚本里 grep 的判断结果总是「不匹配」。
原因把 grep 的输出当成返回值,实际它输出内容并以退出码表达结果。
处置用 grep -q 只看退出码:if grep -q "pattern" file; then … fi。
现象搜到日志里了,但一行里有多个匹配时只算一次。
原因grep -c 统计的是匹配行数而非匹配次数。
处置需要出现次数时用 grep -o 提取后 wc -l,或用 grep -o | wc -l。
排障路径
1先看实际匹配到了什么
grep -o "pattern" file-o 只输出匹配片段;没输出就说明没命中,可逐段简化模式再试。
2带上下文定位报错位置
grep -n -C 3 "FATAL" app.log-n 给行号、-C 3 前后各三行,通常这几行就说明了问题。
3按类型限定搜索范围
grep -rn --include="*.ts" "TODO" src/限定文件类型比全量搜后再过滤快得多。
4脚本里判断内容是否存在
grep -q "ready" app.log静默模式只返回状态码,适合写进健康检查。
5统计各项出现次数
grep -oE "error|warning" app.log | sort | uniq -c | sort -rn-o 不能省;先排序让相同值相邻再计数。
命令示例
递归搜索并带上下文
grep -rn -C 2 "handleError" src/-C 2 表示匹配行前后各显示 2 行,-n 给行号便于跳转。找不到时先确认大小写——grep 默认区分大小写。
输出
src/api/client.ts-42- try {
src/api/client.ts-43- const res = await fetch(url)
src/api/client.ts:44- handleError(res)
--
src/api/retry.ts-18- handleError(new Error("timeout"))从日志里提取并统计 IP 地址
grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' access.log | sort | uniq -c | sort -rn | head-o 只输出匹配到的部分而非整行,这样才能喂给 sort | uniq -c 统计。不加 -o 拿到的是整行,计数没有意义。
输出
1842 203.0.113.7
931 198.51.100.22
407 192.0.2.180只搜索特定类型文件并排除依赖目录
grep -rn --include="*.ts" --include="*.js" --exclude-dir=node_modules "API_KEY" .--include 可重复指定;--exclude-dir 跳过 node_modules 之类的大目录,既快又避免结果被依赖代码淹没。
常见坑与注意事项
- grep 默认区分大小写,搜不到时先试 -i。
- 模式里的元字符(. * + ? [ ])会被当正则解释,搜字面量要加 -F 或转义;搜 a.b 会连 axb 一起命中。
- 递归搜仓库不加 --exclude-dir=node_modules 会产生大量无结果且拖慢速度。
- grep -r 不跟随符号链接,依赖目录若是指向别处的软链会搜不到,需要 -R。
- 用 -o 提取子串时不要忘加,否则 uniq 统计的是整行而非匹配片段。
提示
- grep 默认使用 BRE(基本正则),+、?、| 需转义或用 -E 启用 ERE。
- 递归搜索大目录时加 --exclude-dir 排除 node_modules、.git 等。
- grep -q 用于脚本中判断是否匹配,不输出内容只返回状态码。
- grep -rn --include='*.ts' --exclude-dir=node_modules 只搜指定后缀的源码文件,比先 find 再传参少一层管道且天然跳过二进制。
- grep -o 只输出匹配部分而非整行,配合 sort | uniq -c 可以统计某个字符串在日志里出现的次数分布。
- grep -v -F -f 黑名单.txt 用固定字符串模式按文件排除一批模式,配置类文件批量清理时比写一长串正则更可靠。
常见问题
grep -r 和 grep -R 有什么区别?
小的 r 只递归普通目录和文件,遇到符号链接不跟随;大写的 R 额外会跟随符号链接一起搜。如果代码仓库里 node_modules 或 ~/.cache 之类是指向别处的软链,用 -r 会漏掉其中的内容,用 -R 才搜得到。另外在 GNU grep 里 -r 基本等价于 --recursive,但 macOS 的 BSD grep 两者行为一致。
怎么只搜索某种文件类型的内容?
加 --include:grep -rn --include="*.log" "error" . 只在 .log 文件里搜。多个模式用 --include="*.ts" --include="*.js" 连写即可。相对地,--exclude 可以排除掉 node_modules、dist 这类目录,避免结果里全是依赖代码。
grep 匹配不到明明存在的字符串是什么原因?
最常见是大小写没匹配,grep 默认区分大小写,需要 -i;其次是特殊字符被当成正则元字符,搜 a.b 会匹配到 axb 这类内容,要搜字面量就加 -F 或对元字符转义。再就是文件里有不可见字符或行尾 CRLF(Windows 换行)导致行尾匹配失败,可以直接搜回车符确认。
grep 输出的 -n、-c、-l、-o 各自适合什么场景?
-n 显示行号,方便定位和跳转,是最常加的;-c 只输出匹配行数不输出内容,适合做统计判断;-l 只列出含匹配的文件名,批量改文件前先看它圈定范围;-o 只输出匹配到的部分本身,配合 sort | uniq -c 能把日志里出现最多的关键词统计出来。
怎么一次匹配多个关键词?
两种方式:管道接起来最清晰,grep "error" app.log | grep "timeout" 依次过滤;或者用 -e 一次指定多个模式,grep -e "error" -e "timeout" app.log,效率更高只需扫一遍文件。模式较多时还可以用 -f patterns.txt 从文件读入。
由 巧匠 维护
公开更新于 2026年7月21日,内容持续校对官方文档。