Skip to content

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——流编辑,能对文本做替换、增删改。