grep —— 从海量文本里捞出那一行
grep —— 从海量文本里捞出那一行
分类:04 文本处理 适用:全平台(GNU grep / BSD grep;
ripgrep更快) 一句话:日志检索、配置查错、代码搜索的基础工具,掌握上下文参数能省一半时间。
1. 它解决什么问题
- 在几个 G 的日志里找一次报错,还要看前后几行。
- 统计某个错误出现了多少次。
- 递归搜索目录里哪份配置写了某个值。
- 从命令输出里筛出需要的行。
2. 基础用法
grep 'error' app.log
grep -i 'error' app.log # 忽略大小写
grep -v 'DEBUG' app.log # 反向:不含
grep -c 'error' app.log # 只输出匹配行数
grep -n 'error' app.log # 带行号
grep -l 'timeout' *.log # 只输出含匹配的文件名
grep -L 'pattern' *.log # 输出不含匹配的文件名
grep -H 'error' *.log # 强制显示文件名
grep -h 'error' *.log # 不显示文件名
3. 上下文(排障最重要)
grep -A 5 'ERROR' app.log # 后 5 行
grep -B 5 'ERROR' app.log # 前 5 行
grep -C 5 'ERROR' app.log # 前后各 5 行
grep -A 20 -B 2 'Exception' app.log
日志里的异常堆栈通常是"一行错误 + 几十行堆栈",-A 30 才看得全。
4. 递归与文件筛选
grep -r 'listen 80' /etc/nginx/ # 递归
grep -rn 'Listen 8080' /etc/ # 递归 + 行号
grep -r --include='*.conf' 'root' /etc/nginx/
grep -r --exclude='*.log' --exclude-dir='.git' 'TODO' .
grep -rI 'pattern' /data # -I 跳过二进制文件
--include / --exclude 可多次使用,比事后 | grep 高效。
5. 正则与扩展
grep 'error\|fail' app.log # 基础正则:或
grep -E 'error|fail|timeout' app.log # 扩展正则(推荐)
grep -E '^[0-9]{4}-[0-9]{2}-[0-9]{2}' # 日期开头
grep -P '\d{3,}' app.log # Perl 正则(\d、\b、断言)
grep -o 'user_id=[0-9]*' app.log # 只输出匹配部分
grep -w 'root' /etc/passwd # 全词匹配
grep -x 'exact line' file # 整行匹配
grep -F 'a.b.c' file # 固定字符串(不解释正则,快)
| 参数 | 正则类型 | 说明 |
|---|---|---|
| 默认 | BRE | | \+ \? 需转义 |
-E |
ERE | ` |
-P |
PCRE | 支持 \d、\w、前瞻断言 |
-F |
无 | 按字面量匹配,最快 |
6. 常用组合
统计
grep -c 'ERROR' app.log # 次数
grep -o 'status=[0-9]*' app.log | sort | uniq -c | sort -nr # 分布
grep 'ERROR' app.log | awk '{print $5}' | sort | uniq -c | sort -nr | head
多条件
grep -E 'ERROR|FATAL' app.log # 或
grep 'ERROR' app.log | grep 'order-service' # 与
grep 'ERROR' app.log | grep -v 'healthcheck' # 排除噪音
配合 awk/sed
grep 'POST /api' access.log | awk '{print $7}' | sort | uniq -c | sort -nr | head
grep 'ERROR' app.log | sed 's/.*ERROR //' | head
二进制与压缩文件
grep -a 'pattern' binary.dat # 当文本处理
zgrep 'ERROR' app.log.1.gz # 直接搜 .gz
bzgrep / xzgrep # 其他压缩格式
grep -r --include='*.gz' -l 'x' . # 不会自动解压,需 zgrep
7. 实战场景
7.1 定位一次报错的完整上下文
grep -n -A 40 -B 5 'NullPointerException' app.log | head -80
先拿到行号,再用 sed -n '12345,12390p' app.log 精确查看。
7.2 统计各接口 5xx 数量
grep -E '" 5[0-9]{2} ' access.log | awk '{print $7}' | sort | uniq -c | sort -nr | head -20
7.3 在配置目录里找出所有监听端口
grep -rn -E '^\s*(listen|port)\s' /etc/nginx/ /etc/redis/ 2>/dev/null
7.4 排除日志噪音
grep 'ERROR' app.log \
| grep -v -E 'HealthCheck|ReadinessProbe|/metrics|kube-probe'
7.5 搜索大文件时提速
# 1. 先确认文件大小,考虑只搜尾部
tail -n 500000 app.log | grep 'ERROR'
# 2. 用固定字符串
grep -F 'Connection refused' app.log
# 3. 用 ripgrep(快 5~10 倍)
rg 'Connection refused' /var/log/
8. 常见坑
- 没加引号导致模式被 shell 解释:
grep *.log会展开文件名,模式要用引号。 grep -r会跟软链接目录:加-r(不跟随)或-R(跟随),GNU grep 的-r默认不跟随符号链接。- 二进制文件提示
Binary file matches:加-a或-I。 grep匹配的是行:一行里有多个匹配也只算一行,计数要多用-o。-c与-o组合:grep -o ... | wc -l才是匹配次数,-c是行数。- 中文/编码问题:日志是 GBK 时先
iconv -f gbk -t utf-8,否则匹配不到。 -P不是所有平台都有:BSD/macOS 的 grep 不支持,用ggrep或rg。- 大文件内存:GNU grep 会 mmap,通常没问题;管道输入时逐行处理,但
-A/-B需要缓冲。 --exclude-dir对绝对路径起点无效:从当前目录开始搜更可靠。- 颜色影响脚本解析:
--color=always会插入 ANSI 转义,管道里别开。 grep -v -v不是双重否定,多个-v只生效一次。^与$在-z模式下行为不同:按\0分段时要注意。
9. 速查表
grep 'pat' file # 基础
grep -i 'pat' file # 忽略大小写
grep -v 'pat' file # 反向
grep -c 'pat' file # 行数
grep -n 'pat' file # 行号
grep -C 5 'pat' file # 上下文
grep -A 20 'pat' file # 后 20 行
grep -E 'a|b' file # 扩展正则
grep -P '\d+' file # Perl 正则
grep -o 'k=[0-9]*' file # 只输出匹配
grep -F 'a.b' file # 固定字符串
grep -r --include='*.conf' 'x' /etc # 递归+筛选
grep -rl 'x' . # 只列文件
zgrep 'x' file.gz # 搜压缩包
# 统计
grep -o 'pat' f | sort | uniq -c | sort -nr