Appearance
10|grep 过滤与正则
Linux 基础系列里用管道串过 grep——cat log | grep error 从日志里找含 error 的行。那是最基础的用法。本篇深入讲 grep 的正则语法和常用参数,写脚本时能更精确地过滤文本。
一、grep 做什么
grep 按模式匹配文本行,把匹配的行输出。最简单的用法:
bash
grep error /var/log/messages从 /var/log/messages 找含 "error" 的行。"error" 是最简单的模式——普通字符串,逐字匹配。
二、基础正则
模式里用特殊字符表示一类字符,这就是正则:
| 符号 | 匹配 |
|---|---|
. | 任意一个字符 |
* | 前一个字符出现 0 次或多次 |
^ | 行首 |
$ | 行尾 |
[abc] | abc 中任一个 |
[^abc] | 不是 abc 的任一个 |
例子:
bash
# 找以 ERROR 开头的行
grep '^ERROR' app.log
# 找以 .log 结尾的行(注意 . 在正则里是任意字符,这里要转义)
grep '\.log$' files.txt
# 找 IP 地址(粗略)
grep '[0-9]\.[0-9]\.[0-9]\.[0-9]' access.log注意 . 在正则里是"任意字符",要匹配字面的点要加反斜杠转义 \.。这是初学常犯的错——写 grep .log 会匹配到 "xlog""alog" 之类。
三、扩展正则 -E
基础正则里 +、?、|、() 这些要转义。用 -E(或 egrep)启用扩展正则,这些字符直接能用:
bash
# 找 ERROR 或 WARN
grep -E 'ERROR|WARN' app.log
# 找连续数字(+ 表示一次或多次)
grep -E '[0-9]+' access.log
# 分组
grep -E '(error|fail)' app.log写复杂正则一律用 -E,少写很多反斜杠。
四、常用参数
| 参数 | 作用 |
|---|---|
-i | 忽略大小写 |
-v | 反向匹配(输出不匹配的行) |
-n | 显示行号 |
-c | 只输出匹配行数 |
-l | 只输出有匹配的文件名 |
-r | 递归搜索目录 |
-o | 只输出匹配的部分(不输出整行) |
-A 2 | 匹配行后再显示 2 行 |
-B 2 | 匹配行前显示 2 行 |
-C 2 | 匹配行前后各 2 行 |
-v 反向匹配很常用——排除某些行:
bash
# 找非注释行(不以 # 开头)
grep -v '^#' /etc/ssh/sshd_config
# 排除空行和注释行
grep -vE '^\s*(#|$)' config.conf-A/-B/-C 看错误上下文——报错时连带前后几行:
bash
grep -A 5 'Exception' app.log # 异常行后看 5 行堆栈-o 只取匹配部分——从日志里把所有 IP 提出来:
bash
grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' access.log | sort -u五、-P:Perl 正则
-P 启用 Perl 兼容正则,支持更高级特性(\d、\s、零宽断言)。不是所有 grep 都支持:
bash
# \d 匹配数字
grep -P '\d+\.\d+\.\d+\.\d+' access.log能用 -E 就用 -E,移植性更好。-P 在需要特殊特性时才用,且要确认环境的 grep 支持(GNU grep 支持,BSD/macOS 的不支持)。
六、grep 在管道里的位置
grep 经常接在管道后面过滤前一个命令的输出:
bash
# 从 ps 输出找进程
ps aux | grep nginx
# 但这样会把 grep 自己也匹配出来
ps aux | grep nginx | grep -v grep # 排除 grep 自身更优雅的写法用 grep [n]ginx——模式里把一个字符放中括号,匹配的还是 nginx,但进程名显示的是 grep [n]ginx,不会被自己匹配:
bash
ps aux | grep '[n]ginx'七、性能
大文件里 grep 一般很快。但有几个坑:
贪心匹配——.* 会尽可能多匹配,可能跨过预期边界:
bash
# 想匹配 <html> 标签,但 .* 贪婪会匹配到最后一个 >
grep '<.*>' file用非贪婪(-P 支持 .*?)或更精确的模式避免。
大文件重复 grep——对同一大文件多次 grep,不如一次 awk 处理:
bash
# 慢:扫三遍
grep ERROR log
grep WARN log
grep INFO log
# 快:扫一遍
awk '/ERROR/{e++} /WARN/{w++} /INFO/{i++} END{print e,w,i}' log八、grep 还是 grep -E 还是 rg
grep:基础正则,移植性最好grep -E:扩展正则,写脚本首选rg(ripgrep):更快、默认递归、默认忽略 .gitignore,但不是系统自带
生产脚本要可移植用 grep -E。交互式搜索用 rg 更顺手。
学会了之后
grep 是文本过滤的主力。正则分基础(.、*、^、$、[])和扩展(+、?、|、(),用 -E)。常用参数里 -v(反向)、-n(行号)、-A/-B/-C(上下文)、-o(只取匹配)最高频。
下一篇讲 sed——流编辑,能对文本做替换、增删改。