grep Cheatsheet - Linux Text Search Reference
Fishing an error out of a log, finding every reference to an identifier, or testing a condition in a script all reduce to searching lines by pattern, and four flags cover most of it: -r, -i, -C n for context, and -E for extended regex. Mastering those four dissolves the most common complaint about grep — finding the match but missing the context around it. The sheet spans basic search, recursion, regular expressions, context, multiple patterns and common patterns. The multi-pattern group gives the escape hatches worth knowing: repeating -e, reading patterns from a file with -f, and constraining the file set with --include and --exclude. One performance note: sweeping node_modules, .git or dist without filtering makes --exclude-dir a requirement rather than an optimisation. The regex dialect trap matches sed: under BRE, +, ? and | need escaping unless you pass -E. The boundary is drawn in the scenario group: grep filters lines, awk aggregates columns, and rg respects .gitignore.
Typical Use Case
For developers who search logs and code every day. grep has three traps worth stating up front: the default is BRE, where + ? and | must be escaped or -E used; you cannot drop -o when extracting fragments, or counting will be done per line rather than per match; and recursive searches of a large tree need --exclude-dir for node_modules and .git or a single search can stall for minutes. This sheet is organised into six groups and works well as a troubleshooting checklist.
Basic Search 7
grep "pattern" filegrep -i "pattern" filegrep -v "pattern" filegrep -c "pattern" filegrep -n "pattern" filegrep -o "pattern" filegrep -q "pattern" fileRecursive 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" fileContext 4
grep -A 3 "pattern" filegrep -B 2 "pattern" filegrep -C 3 "pattern" filegrep -A 3 -B 2 "pattern" fileMultiple Patterns & Files 6
grep -e "pattern1" -e "pattern2" filegrep -f patterns.txt filegrep "pattern" file1 file2grep "pattern" *.loggrep -H "pattern" filegrep -h "pattern" file1 file2Common 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 "^$"Parameter matrix
| Parameter | Effect | Example |
|---|---|---|
-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/ |
Common pitfalls
Symptom模式里写了 + ? | 却匹配不到。
Causegrep 默认使用基本正则(BRE),这三个符号在 BRE 下是字面量。
Fix加 -E 启用扩展正则,或把这些符号转义成 \+ \? \|。
Symptom想统计某项出现多少次,结果比实际多很多。
Cause没加 -o,uniq 统计的是整行而非匹配片段。
Fix加 -o 只输出匹配部分:grep -oE "模式" file | sort | uniq -c | sort -rn。
Symptom搜 "cat" 结果把 concatenate 也匹配出来了。
Cause模式没有单词边界约束。
Fix加 -w(或 BRE 下用 \<cat\>)限定为完整单词。
Symptom递归搜项目目录卡住,几分钟不出结果。
Cause扫进了 node_modules、.git 等海量小文件目录。
Fix加 --exclude-dir="node_modules" --exclude-dir=".git" 限定范围。
Symptom搜文件名里的点号,结果匹配到了任意字符。
Cause.` 是正则元字符,字面使用未转义。
Fix写成 \. 转义,或用 grep -F 按字面匹配。
Symptom脚本里 grep 的判断结果总是「不匹配」。
Cause把 grep 的输出当成返回值,实际它输出内容并以退出码表达结果。
Fix用 grep -q 只看退出码:if grep -q "pattern" file; then … fi。
Symptom搜到日志里了,但一行里有多个匹配时只算一次。
Causegrep -c 统计的是匹配行数而非匹配次数。
Fix需要出现次数时用 grep -o 提取后 wc -l,或用 grep -o | wc -l。
Troubleshooting
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 不能省;先排序让相同值相邻再计数。
Command Examples
Recursive search with context
grep -rn -C 2 "handleError" src/-C 2 表示匹配行前后各显示 2 行,-n 给行号便于跳转。找不到时先确认大小写——grep 默认区分大小写。
Output
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"))Extract and count IP addresses from a log
grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' access.log | sort | uniq -c | sort -rn | head-o 只输出匹配到的部分而非整行,这样才能喂给 sort | uniq -c 统计。不加 -o 拿到的是整行,计数没有意义。
Output
1842 203.0.113.7
931 198.51.100.22
407 192.0.2.180Restrict to file types and skip dependency directories
grep -rn --include="*.ts" --include="*.js" --exclude-dir=node_modules "API_KEY" .--include 可重复指定;--exclude-dir 跳过 node_modules 之类的大目录,既快又避免结果被依赖代码淹没。
Common Pitfalls
- grep is case-sensitive by default; try -i when nothing matches.
- Metacharacters (. * + ? [ ]) are interpreted as regex, so searching a.b also matches axb — use -F or escape them.
- Recursive searches without --exclude-dir=node_modules are slow and swamped by dependency code.
- grep -r does not follow symlinks, so content behind a symlinked dependency directory is missed; use -R.
- When extracting with -o, do not forget the flag — otherwise uniq counts whole lines rather than the matched fragments.
Tips
- grep uses BRE (basic regex) by default; +, ?, | must be escaped or enable ERE with -E.
- When searching large directories recursively, exclude node_modules, .git, etc. with --exclude-dir.
- grep -q is useful in scripts to test for a match — it outputs nothing and returns only an exit code.
FAQ
What is the difference between grep -r and grep -R?
Lowercase -r recurses through normal directories and files but does not follow symlinks; uppercase -R does follow them. If node_modules or ~/.cache in your repo contains symlinks pointing elsewhere, -r silently misses their contents while -R finds them. On GNU grep -r is essentially --recursive, though BSD grep on macOS treats them the same.
How do I search only within certain file types?
Use --include: grep -rn --include="*.log" "error" . restricts the search to .log files. Chain several with --include="*.ts" --include="*.js". Symmetrically, --exclude lets you skip directories like node_modules or dist so results are not buried in dependency code.
Why does grep fail to match a string that is clearly there?
Most often it is case: grep is case-sensitive by default and needs -i. Next, metacharacters are being interpreted — searching a.b also matches axb, so add -F for a fixed string or escape the metacharacters. A third cause is invisible characters or CRLF line endings defeating a $ anchor, which you can isolate by grepping for a carriage return directly.
When should I use grep -n, -c, -l or -o?
-n prints line numbers for quick navigation and is the flag you add most. -c outputs only the count of matching lines, ideal for scripted checks. -l lists just the filenames that contain a match, useful for scoping a bulk edit. -o prints only the matched portion itself, which piped into sort | uniq -c gives you frequency counts of tokens in a log.
How do I match several keywords at once?
Two ways. Piping is the clearest: grep "error" app.log | grep "timeout" filters sequentially. Or pass several patterns with -e in one pass: grep -e "error" -e "timeout" app.log, which scans the file only once and is faster. With many patterns, read them from a file via -f patterns.txt.
Official References
Each command links to its official documentation below, so you can verify the latest usage and read deeper.
Maintained by LaoHand
Publicly updated on Jul 21, 2026, continuously proofread against official docs.
Contact Us
Wrong command or description? Send us corrections, business inquiries or product feedback by email.
Contact Us