BRE 与 ERE 的差异
POSIX 定义了两套正则语法:基础正则 BRE 与扩展正则 ERE。它们的差别只有一个方向却非常容易记反:在 BRE 里 +、?、|、(、)、{、} 默认是普通字符,想要元字符语义必须加反斜杠;在 ERE 里这些字符默认就是元字符,想匹配字面值反而要转义。锚点 ^ 与 $、反向引用 \1 在两者中写法相同。
基本信息
| BRE | 分组写 \(…\),量词写 \{n,m\},交替写 a\|b |
|---|---|
| ERE | 分组写 (…),量词写 {n,m},交替写 a|b,字面值需转义 |
| 工具默认 | grep 与 sed 默认 BRE(-E 切 ERE),awk 默认 ERE |
| 共同点 | ^ 与 $ 锚定、\1 反向引用在两种语法里一致 |
典型使用场景
- 写 grep 规则:需要分组或交替时加 -E 更省心,否则得逐个转义
- 改 sed 脚本:把 BRE 脚本迁移到 ERE 时,转义方向要整体调整,容易漏改
- 读别人写的旧脚本:看到 \( 与 \{ 就说明是 BRE,别按 ERE 直觉理解
- 跨平台执行:BSD 系工具与 GNU 工具的扩展支持不同,依赖扩展会让脚本在另一台机器上失效
- 排查匹配不到字面加号:多半是把 BRE 与 ERE 的转义方向记反了
同一需求两种写法
同一需求两种写法
grep '\(foo\)\{2,3\}' file # BRE:分组与量词都要转义
grep -E '(foo){2,3}' file # ERE:分组与量词直接写
grep -E 'a\+' file # ERE 中匹配字面加号,必须转义
grep 'a+' file # BRE 中 a+ 就是字面 a 加号,不是「一个或多个 a」
sed -n '/\(ab\)\+/p' file # GNU sed 在 BRE 下也认 \+,属扩展用法
awk '$1 ~ /^(GET|POST)$/' file # awk 的匹配直接使用 ERE元字符写法对照
| 语义 | BRE 写法 | ERE 写法 |
|---|---|---|
| 匹配字面加号 | + | \+ |
| 一个或多个 | \+(GNU 扩展)或重复写法 | + |
| 分组 | \(abc\) | (abc) |
| 交替 | a\|b | a|b |
| 区间量词 | a\{2,3\} | a{2,3} |
| 反向引用 | \1 | \1 |
| 匹配字面括号 | ( | \( |
GNU 的 grep 与 sed 在 BRE 下额外接受 \+、\?、\| 这类写法,看起来能省掉 -E,但这些是实现的扩展;换到 BSD 系或精简环境上可能直接失效,可移植脚本仍应显式使用 -E。
bash 的 [[ string =~ regex ]] 使用 ERE(并带有少量实现相关差异),而 grep 默认是 BRE;同一脚本里混用两种工具时最容易在这里出错,调试时先确认每条规则走的是哪套语法。