深色模式
命令行工具里的正则
概述
正则一到命令行里,最常见的问题不是“语法不会写”,而是根本不知道当前工具在用哪套规则。grep、sed、awk 都能写正则,但默认模式和支持边界并不一样。
另一类高频混淆是把 Shell 通配符当成正则。两边都长着 *、?、[],但匹配机制根本不是一回事。先把这层分开,后面的使用体验会稳定很多。
grep 默认通常站在 BRE 这一边
传统 grep 默认使用的是 BRE 语境,所以这类写法经常要带反斜线:
sh
grep '\(ab\)\{2\}' file.txt如果想用 ERE 的写法,常见方式是显式加 -E:
sh
grep -E '(ab){2}' file.txtegrep 本质上就是 grep -E 的老名字。很多系统里还能用,但新文档一般更推荐直接写 grep -E,可读性更直接。
sed 的感觉和 grep 很像
sed 默认也更接近 BRE,所以很多老例子里满眼都是反斜线:
sh
sed -n '/\(error\)\{2\}/p' file.txt切到 ERE 时,常见写法是 sed -E。在部分 GNU 环境里也能看到 -r,但跨平台写法通常更推荐 -E。
sh
sed -E -n '/(error){2}/p' file.txt这一点在 macOS 和 Linux 混用时尤其值得注意。别把某个系统上的扩展行为,误当成了 sed 的普遍规则。
awk 更接近 ERE 的使用体验
awk 里的正则通常更接近 ERE。像分组、选择、次数限定这类写法,一般不用写成 BRE 那么费劲。
例如匹配日志级别:
sh
awk '/^(INFO|WARN|ERROR)$/' file.txt这种写法对很多读者来说,比 grep 默认模式更符合直觉,这也是不少人觉得 awk 正则“顺手一点”的原因。
grep -P 不是 POSIX,那是另一条路线
grep -P 的意思通常不是“更强一点的 ERE”,而是让 grep 尝试按 Perl 风格那一派来解释模式。
这件事要注意两个边界:
-P不属于 POSIX 语义- 某个系统上的
grep是否支持-P,要看具体实现
一旦写到 \d、环视、非贪婪量词,通常已经不是 BRE 或 ERE 的话题,而是在依赖 Perl 风格正则或兼容它的实现。
ripgrep 和 perl 为什么体验又不一样
ripgrep、perl、pcre2grep 这类工具,代表的是另一类使用体验,但它们也不是完全同一派。
perl 和 pcre2grep 更靠近 Perl 风格正则那条路线,很多高级语法本来就是沿着这条线发展起来的。
ripgrep 默认则更接近 Rust regex crate 那种强调性能可预测性的实现,默认并不等于 PCRE。只有显式开启 -P 时,它才会切到 PCRE2 语境。
所以不能把在 perl 里能跑通的模式,直接假定为 grep、sed、awk、ripgrep 默认模式都能照搬。
Shell glob 不是正则
这部分单独拎出来讲,是因为它太容易混。
在 Shell 里:
*.log通常是文件名匹配模式file?.txt也是路径名展开规则[ab]*仍然是在做路径匹配
这类东西属于 glob,不是正则。
它和正则最像的地方,是也用了 *、?、[]。但含义并不一样:
| 写法 | glob 里的常见含义 | 正则里的常见含义 |
|---|---|---|
* | 任意长度字符串 | 前一个表达式重复零次或多次 |
? | 任意单个字符 | 前一个表达式重复零次或一次 |
[] | 字符集合 | 字符集合 |
[] 这项两边比较像,但 * 和 ? 的核心逻辑完全不同。把 glob 当成正则看,写出来的模式通常一上手就跑偏。
实战里怎么选
- 要可移植、要兼顾传统 Unix 工具,优先按 POSIX 思路写
- 明确在
grep -E、sed -E、awk里工作时,按ERE语境理解 - 需要
\d、环视、命名分组这类能力时,不要硬拗 POSIX,直接确认工具是否支持 Perl 风格实现 - 看到通配符先问一句:这到底是正则,还是 Shell 在做路径展开
命令行里的正则,真正难的不是语法本身,而是别把不同系统、不同时代、不同工具的行为揉成一锅。
