优秀的编程知识分享平台

网站首页 > 技术文章 正文

grep sed awk 的正则表达式不支持 \d? | BRE ERE PCRE

nanyue 2024-09-10 16:11:54 技术文章 6 ℃

前言

grepsedawk 是 linux 操作文本的三大利器,合称文本三剑客,它们也是 linux 系统很常用的命令。grepsedawk 都支持正则表达式,不过我们中的一些人可能遇到过这样的情况:特定的正则表达式不适用于某些 Linux 命令。例如,正则表达式 \dsedawk 不支持,grep 命令不使用 -P 参数同样也是不支持。但是,相同的正则表达式适用于 Java 或 Python。这可能会让我们感到困惑。下面,我们看下此类问题并解释为什么会发生这种情况。

问题描述

我们创建一个测试文本 a.txt 做实验,a.txt内容如下:

[root@z2024 tmp]# cat a.txt
Hello,Can you see me?
127.0.0.1 example.com
dddwww
0123456789
abcdefg

正则表达式 [0-9] 是匹配一个数字。我们使用 [0-9]测试下grepsedawk命令是否可以支持:

[root@z2024 tmp]# grep '[0-9]' a.txt
127.0.0.1 example.com
0123456789

[root@z2024 tmp]# sed -n '/[0-9]/p' a.txt
127.0.0.1 example.com
0123456789

[root@z2024 tmp]# awk '/[0-9]/' a.txt
127.0.0.1 example.com
0123456789
[root@z2024 tmp]#

看起来没问题

在正则表达式中 \d[0-9] 的缩写形式,我们使用 \d看这三命令是否可以支持:

[root@z2024 tmp]# grep '\d' a.txt
dddwww
abcdefg
[root@z2024 tmp]# grep -E '\d' a.txt
dddwww
abcdefg
[root@z2024 tmp]# grep -P '\d' a.txt
127.0.0.1 example.com
0123456789

[root@z2024 tmp]# sed -n '/\d/p' a.txt
dddwww
abcdefg
[root@z2024 tmp]# sed -nr '/\d/p' a.txt
dddwww
abcdefg

[root@z2024 tmp]# awk '/\d/' a.txt
dddwww
abcdefg
[root@z2024 tmp]#

从上面可以看得到,只有 grep加上 -P参数才是对的。

解释上面这个现象,可以看下 man grep

grep understands three different versions of regular expression syntax: “basic” (BRE), “extended” (ERE) and “perl” (PCRE). In GNU grep there is no difference in available functionality between basic and extended syntaxes. In other implementations, basic regular expressions are less powerful. The following description applies to extended regular expressions; differences for basic regular expressions are summarized afterwards. Perl-compatible regular expressions give additional functionality, and are documented in pcresyntax(3) and pcrepattern(3), but work only if PCRE is available in the system.

grep 支持三种不同版本的正则表达式, 默认是 BRE。那 BREEREPCRE 有什么区别呢?

-E, --extended-regexp
    Interpret PATTERN as an extended regular expression (ERE, see below).
-G, --basic-regexp
    Interpret PATTERN as a basic regular expression (BRE, see below).  This is the default.
-P, --perl-regexp
    Interpret the pattern as a Perl-compatible regular expression (PCRE).  This is experimental and grep -P may warn of unimplemented features.

BRE, ERE, and PCRE

  • BRE – Basic Regular Expressions
  • ERE – Extended Regular Expressions
  • PCRE – Perl Compatible Regular Expressions

正则表达式的 POSIX 规范,分为基本型正则表达式(Basic Regular Expression,BRE)和扩展型正则表达式(Extended Regular Expression,ERE)两大流派。再后来出现了 Perl 的正则表达式,它已经演化成了 PCRE(Perl Compatible Regular Expressions)。PCRE 已经成为一种事实上的标准,它拥有一组丰富而强大的原子表达式。PCRE 没有“基本”或“扩展”级别。

BRE 是最古老的正则表达式语法。顾名思义,它只支持非常基本的功能。例如,标准 POSIX BRE 不支持很多你知道的正则表达式功能,如前面说的 \d,还有 \s , | , ?+ 等等。另外,BRE 要求将元字符 ( ){ } 进行转义 \(\)\{\} ,而扩展正则表达式 (ERE)则不用。

PCRE 的语法比 BREERE 更强大、更灵活。下面看一下仅在 PCRE 中可用的一些功能:

  • Look-around - 前后查找
  • 非贪婪匹配 - *?+?{m, }?
  • 区分大小写/不区分大小写的匹配 - (?i)(?-i)
  • 用于匹配数字,非数字字符等的简写 - \d\D

grepvised 都属于 BREsed 使用 -r 参数就可以切换成 EREegrepawk 则属于 ERE。所以 grep 使用 PCRE 正则表达式 -P 参数才可以支持 \d

Grep on Linux and Mac

在 Mac 上 的 grep 命令没有 -P 这个选项(我较新的 Mac 系统 sonama 也没有),查看 grep version 原来它是 BSD grep,linux 上系统的 grep 是属于 GNU grep。BSD 版本使用 POSIX 兼容正则表达式,GNU 版本使用 PCRE

$ grep -V
grep (BSD grep, GNU compatible) 2.6.0-FreeBSD

当然你也可以通过 HomeBrew 自行安装 GNU grep,吐槽下苹果这么牛逼的命令行工具也不更新下。

总结

不同的工具可能使用不同版本的正则表达式,大家使用的时候可以看下它的文档或者查阅相关资料,对于 sedawk 无法使用 PCRE ,懂 perl 的同学也可以使用它来替代。如果您在阅读过程中发现了任何问题,或者有任何可以改进的地方,欢迎留言或者私信我。


参考链接:
https://en.wikipedia.org/wiki/Regular_expression
https://en.wikibooks.org/wiki/Regular_Expressions/POSIX_Basic_Regular_Expressions
https://www.baeldung.com/linux/digit-pattern-not-supported-by-grep-regex
https://xebia.com/blog/learning-grep/

Tags:

最近发表
标签列表