讲解
grep 在文件内容里按模式搜索,把匹配的行整行打印出来:grep "ERROR" app.log 找出日志里所有报错行。它是排查问题的第一工具——日志里有没有报错、代码里哪里调用了某个函数、配置里某个 key 是什么值,都是 grep 一句话的事。
常用选项要形成肌肉记忆:-i 忽略大小写;-n 显示行号;-v 反向匹配(显示不包含模式的行,过滤噪声专用);-c 只统计匹配行数;-r 递归搜索整个目录;-l 只列出包含匹配的文件名而不显示内容;-w 整词匹配(避免 log 匹配到 login)。模式默认支持基础正则表达式,加 -E 启用扩展正则,可以写 "ERROR|WARN" 这样的「或」。
grep 有个影响脚本的行为要记住:有匹配时退出码是 0,没有匹配时退出码是 1,出错是 2。在开了 set -e 的脚本里,「没匹配到」会直接让脚本退出——不是 bug,是特性。需要允许无匹配时写成 grep ... || true。
示例
# 找出所有报错行
grep "ERROR" app.log
# 显示行号;忽略大小写
grep -n "INFO" app.log
grep -i "hello" hello.txt
# 反向匹配:去掉 INFO 行,只看重要信息
grep -v "INFO" app.log
# 统计报错次数;递归搜索目录
grep -c "ERROR" app.log
grep -rn "文档" docs
# -E 扩展正则:ERROR 或 WARN
grep -E "ERROR|WARN" app.log
# 无匹配时退出码为 1,脚本里要妥善处理
grep "不存在的内容" notes.txt || echo "没有匹配(退出码 1)"
常见坑
- set -e 脚本里 grep 无匹配导致退出:退出码 1 触发脚本中断。预期可能无匹配时写 || true。
- 大小写没考虑:日志里 Error、ERROR、error 都有,先加 -i 再说找不到。
- 用 grep -P 写了 Perl 正则:-P 是 GNU 扩展,macOS 的 BSD grep 没有。用 -E 的扩展正则通常就够了。
- 大日志直接 grep 输出刷屏:配合 head 截断或重定向到文件,后面管道一章会讲组合技。
小结
grep 按模式筛选行,-i -n -v -c -r -w 是核心选项,-E 启用扩展正则;无匹配退出码为 1,脚本里记得处理。下一节学习把命令串起来的法宝:管道与重定向。