当前位置:首页>Linux>Linux 正则表达式三套标准对比:BRE/ERE/PCRE 一次搞懂

Linux 正则表达式三套标准对比:BRE/ERE/PCRE 一次搞懂

  • 2026-10-11 06:12:47
Linux 正则表达式三套标准对比:BRE/ERE/PCRE 一次搞懂
Linux 下用正则,最烦的不是语法本身,而是同一个写法在不同的命令里含义不一样。

比如我想匹配 aa 或 abb:

grep 'a\{2,3\}' file   # 得加反斜杠grep -E 'a{2,3}' file  # 不用加sed 's/a\{2,3\}/X/' file  # 又得加

加不加反斜杠、加不加 -E、sed 和 grep 还不一样……每次都得现查。今天把这套东西理清楚,以后不再纠结。

三种正则标准:BRE、ERE、PCRE

Linux 里正则表达式不是只有一种"写法",而是三套标准共存。它们的核心差异就一个:哪些元字符需要转义。

BRE(基本正则)
ERE(扩展正则)
PCRE(Perl 兼容)
标准
POSIX 定义,最基础
POSIX 定义,BRE 扩展
Perl 语言正则移植
转义规则
( ) { } | + ?
 需转义
直接使用,不需转义
直接使用,不需转义
高级特性
不支持
不支持
非贪婪、零宽断言、命名分组等
代表命令
grep
、sed(默认)
grep -E
、awk、sed -r
grep -P
(GNU)

BRE(Basic Regular Expression)

最基础的标准,grep 和 sed 默认用的就是它。特点:特殊字符当成普通字符,要发挥正则作用得加反斜杠。

直接可用的元字符:

  • . 匹配任意单个字符
  • * 匹配前一个字符 0 次或多次
  • ^ 匹配行首
  • $ 匹配行尾
  • [] 字符集、[^] 否定字符集
  • \ 转义

加 \ 才发挥特殊含义的元字符:

\( ... \)   分组\{n,m\}     范围次数\|          或操作

ERE(Extended Regular Expression)

BRE 的升级版,不需要转义特殊字符了。( ) { } | + ? 直接写,不用加反斜杠。还多了一些元字符:

  • + 匹配 1 次或多次(BRE 没有)
  • ? 匹配 0 次或 1 次(BRE 没有)
  • | 或操作(直接写)
  • ( ) 分组(直接写)
  • {n,m} 精确次数(直接写)

一句话总结:能用 ERE 就尽量用 ERE,少敲反斜杠,少出错。

PCRE(Perl Compatible Regular Expression)

功能最强的标准,支持高级特性:非贪婪匹配 *?、+?、??,零宽断言 (?=...)、(?<=...),命名分组 (?P<name>...),条件表达式,递归模式等。只有 GNU grep 的 -P 支持,其他命令基本用不上 PCRE。

各命令怎么用正则(附测试示例)

grep

默认 BRE,-E 切 ERE,-P 切 PCRE(GNU grep 特有)。

准备一个测试文件:

# 创建测试数据cat > /tmp/test.txt <<'EOF'applebananaaaaaaaaaaababbabbb123abc123EOF

示例 1:匹配 a 出现 2 到 3 次

# BRE:花括号需要转义$ grep 'a\{2,3\}' /tmp/test.txtaaaaaaaaa          # 注意:匹配的是前3个a,不是整行# ERE:直接写$ grep -E 'a{2,3}' /tmp/test.txtaaaaaaaaa          # 同上

⚠️ a\{2,3\} 匹配的是"连续 2 到 3 个 a",所以 aaaa 里的前 3 个 a 命中,整行显示。如果你要精确匹配"整行只有 2 到 3 个 a",得加上行首行尾锚定:grep -E '^a{2,3}$' /tmp/test.txt。

示例 2:匹配 apple 或 banana(或操作)

# BRE:竖线需要转义$ grep 'apple\|banana' /tmp/test.txtapplebanana# ERE:竖线直接写$ grep -E 'apple|banana' /tmp/test.txtapplebanana

示例 3:PCRE 的非贪婪匹配

$ echo"abbb" | grep -P 'ab+?'# 非贪婪,只匹配"ab"$ echo"abbb" | grep -P 'ab+'# 贪婪,匹配"abbb"

sed

默认 BRE,-r(GNU)或 -E(BSD/macOS)切 ERE。不同系统参数名不同,记 -r 就行。

示例 1:替换 apple 或 banana

# BRE:竖线需要转义$ sed 's/apple\|banana/FRUIT/g' /tmp/test.txt# ERE:竖线直接写$ sed -r 's/apple|banana/FRUIT/g' /tmp/test.txt

示例 2:把 a 出现 2 到 3 次替换为 X

# BRE$ echo"aa aaa aaaa" | sed 's/a\{2,3\}/X/g'X X Xa# ERE$ echo"aa aaa aaaa" | sed -r 's/a{2,3}/X/g'X X Xa

示例 3:提取文件扩展名

$ echo"archive.tar.gz" | sed -r 's/.*\.(.*)/\1/'gz

vim

vim 有自己的正则语法,核心是 magic 级别,决定了哪些字符要转义、哪些不要。

模式
名称
规则
\m
magic(默认)
+、()、{}、|
 需要 \ 转义
\v
very magic(推荐)
接近 ERE,大部分元字符不用转义
\V
very nomagic
绝大多数符号当普通文本,适合字面查找

修饰符写在正则最开头,只对当前命令生效。

# \m 默认模式:+ 需要转义/^[0-9]\+$# \v 模式:+ 不需要转义/\v^[0-9]+$# \V 模式:() 是普通文本,适合搜字面量/\Vhello(123)

搜索和替换命令都支持:

:%s/[0-9]\+/NUM/g:%s/\v[0-9]+/NUM/g

如果你想永久默认启用 very magic,可以写入 .vimrc:

set magicnnoremap / /\vvnoremap / /\v

ℹ️ \v 只作用于当前这条命令,下次搜索要重新写。[] 字符集规则在所有 magic 模式下都一致,POSIX 类 [[:digit:]] 通用。

find

-name 用的是 shell 通配符,不是正则。要用正则得用 -regex。

示例 1:找 .txt 结尾的文件

# find -regex 默认是 emacs 风格(类似 BRE)$ find . -regex ".*\.txt$"# 指定 ERE$ find . -regextype posix-extended -regex ".*\.(txt|md)$"

示例 2:找文件名以数字开头的文件

# 先在 /tmp 创建几个测试文件$ touch /tmp/1_file.txt /tmp/2_data.log /tmp/abc.txt$ find /tmp -maxdepth 1 -regextype posix-extended \    -regex '.*/[0-9]+_.*'/tmp/1_file.txt/tmp/2_data.log

ℹ️ find 的 -regex 匹配的是完整路径(含目录前缀),不是单纯的文件名。所以上面示例里写的是 .*/[0-9]+_.*,中间多了一个 /。

awk

awk 默认使用 ERE,最省心,不用考虑转义。

# 准备测试数据$ cat > /tmp/score.txt <<'EOF'张三 85李四 92王五 78赵六 100EOF# 打印分数在 80 到 99 之间的行$ awk '$2 ~ /^[89][0-9]$/ {print}' /tmp/score.txt张三 85李四 92# 打印分数是三位数的行(100)$ awk '$2 ~ /^[0-9]{3}$/ {print}' /tmp/score.txt赵六 100

POSIX 字符类

写正则时经常见到 [[:digit:]] 这种写法——双层方括号,外层是字符集,内层 [:xxx:] 是 POSIX 预定义的字符类。

好处:跨平台兼容,多语言环境下比 [0-9] 更可靠。

不建议硬记住,用的时候来查就行:

POSIX 字符类
等价简写
含义
[[:alnum:]][0-9A-Za-z]
字母和数字
[[:alpha:]][A-Za-z]
字母
[[:blank:]][ \t]
空格和制表符
[[:cntrl:]][\x00-\x1F\x7F]
控制字符
[[:digit:]][0-9]
数字
[[:graph:]][\x21-\x7E]
可见字符(不含空格)
[[:lower:]][a-z]
小写字母
[[:print:]][\x20-\x7E]
可打印字符(含空格)
[[:punct:]]
标点符号集
标点符号
[[:space:]][ \t\n\r\f\v]
所有空白字符
[[:upper:]][A-Z]
大写字母
[[:xdigit:]][0-9A-Fa-f]
十六进制数字

测试一下 [[:digit:]] 和 [0-9] 的差异:

$ echo"123" | grep '[[:digit:]]\+'# BRE √$ echo"123" | grep -E '[[:digit:]]+'# ERE √# POSIX 字符类在 BRE 和 ERE 下都能用,兼容性最好

三个最常搞混的场景

1. grep 没加 -E,花括号不生效

# 你以为在匹配 2 到 3 个数字$ echo"12" | grep '[0-9]{2,3}'# 啥也不返回——花括号被当普通字符了!# 正确写法:BRE 需要转义,或者开 ERE$ echo"12" | grep '[0-9]\{2,3\}'# √$ echo"12" | grep -E '[0-9]{2,3}'# √

2. sed 和 grep 转义不一致

# grep -E 不需要转义花括号$ grep -E 'a{2}' file      # √# sed 默认 BRE,需要转义$ sed 's/a{2}/X/' file     # ✗ 花括号没转义,不起作用$ sed 's/a\{2\}/X/' file    # √

3. find -name 和 -regex 不是一回事

$ find . -name "*.txt"# 这是通配符,不是正则$ find . -regex ".*\.txt$"# 这才是正则$ find . -regex "*.txt$"# ✗ 正则里 * 不代表任意字符串!

写在最后

Linux 正则的核心矛盾就一个:不同命令默认的正则标准不同,转义规则跟着变。

记住这几条够了:

  • grep、sed 默认 BRE,grep -E、awk 默认 ERE
  • 能用 ERE 就用 ERE,少敲反斜杠
  • vim 搜索用 \v 开头,跟 ERE 差不多
  • find 用 -regex 才是正则,-name 是通配符
  • POSIX 字符类跨平台最稳,不用记等价写法

下次写正则不确定要不要转义,直接上 -E 或 \v,少踩坑。


如果你在正则上踩过坑,欢迎留言分享。觉得有用的话点个在看,转发给同样在 Linux 下挣扎的同事。

关注「扶锐随笔」,后续还有更多 Linux 实用技巧。

最新文章

随机文章