更新

更新

grep默认情况下,它们sed都被描述为使用“基本正则表达式”(“BRE”)。 BRE 描述得很好这里

但考虑一下这个输出:

# echo '    aaaaa   ' | grep '\(aaaaa\|bbbbb\)'
    aaaaa
# echo '    aaaaa   ' | sed '/\(aaaaa\|bbbbb\)/ s/ /_/g'
    aaaaa

在第一个命令中,\( ... \| ... \)语法行为明确as (X OR Y),因为输出通过了grep

在第二个命令中,\( ... \| ... \)语法显然没有采取行动as (X OR Y),因为空格没有更改为下划线。

(相比之下,两个都命令识别\+为“一次或多次重复”)

发生什么事了?为什么 FreeBSD 中似乎有两种 BRE,其中一种可以识别另一种不能识别的语法?

更深层次的问题是,许多项目都希望通过 BRE 来提供对其他类 UNIX 系统的可移植性。但这表明,即使 BRE 跨平台也不太可能相同,如果它们甚至不可能相同的话之内个人平台。啊?

答案1

链接文章中的描述是错误的。

实际的 POSIX 定义指出:

前面带有未转义的 <backslash> ( '\' ) 的普通字符的解释是未定义的,除了[ (){}、数字和括号内的表达式]

普通字符定义为除 BRE 特殊字符.[^$*和反斜杠本身之外的任何字符。

因此,与该页面声明不同,\+BRE 中 未定义 , 也是如此\|

+一些正则表达式实现将它们定义为与ERE 相同|,尤其是 GNU 的。但您不应该指望这一点,而应该坚持定义的功能。

当然,这里的问题是 ERE 交替运算符|在 BRE 中根本不存在,并且 ERE 的等价物+非常丑陋(它是\{1,\})。所以您可能想改用 ERE。

答案2

$ echo '    aaaaa   ' | sed 's/aaaaa|bbbbb/_/g'
    aaaaa
$ echo '    aaaaa   ' | sed -E 's/aaaaa|bbbbb/_/g'
    _
$ echo '    aaaaa   ' | sed -r 's/aaaaa|bbbbb/_/g'
    _
$ echo '    aaaaa   ' | sed -E '/(aaaaa|bbbbb)/ s/ /_/g'
____aaaaa___
$ echo '    aaaaa   ' | sed -E '/aaaaa|bbbbb/ s/ /_/g'
____aaaaa___

or不是 BRE(基本正则表达式)。您需要-E指定扩展布雷。

GNU 或 BSD Sed 中的正则表达式交替/或运算符 (foo|bar)

更新

为什么 grep 有效?

我们可以选择我们想要使用的模式grep

  -E, --extended-regexp     PATTERN is an extended regular expression
  -F, --fixed-strings       PATTERN is a set of newline-separated strings
  -G, --basic-regexp        PATTERN is a basic regular expression
  -P, --perl-regexp         PATTERN is a Perl regular expression
  -e, --regexp=PATTERN      use PATTERN as a regular expression

通过使用这些开关,我们可以看到grep确实默认为 BRE,并且 OP 表达式因 ERE 而失败:

$ echo '    aaaaa   ' | grep '\(aaaaa\|bbbbb\)'
    aaaaa
$ echo '    aaaaa   ' | egrep '\(aaaaa\|bbbbb\)'
$ echo '    aaaaa   ' | grep -E '\(aaaaa\|bbbbb\)'
$ echo '    aaaaa   ' | grep -G '\(aaaaa\|bbbbb\)'
    aaaaa
$ echo '    aaaaa   ' | grep -G 'aaaaa\|bbbbb'
    aaaaa
$ echo '    aaaaa   ' | grep -G 'aaaaa|bbbbb'
$ echo '    aaaaa   ' | grep -E 'aaaaa|bbbbb'
    aaaaa
$ echo '    aaaaa   ' | grep -E 'aaaaa\|bbbbb'
$ echo '    aaaaa   ' | grep -G 'bbbbb\|aaaaa'
    aaaaa
$ echo '    aaaaa   ' | grep -E 'bbbbb\|aaaaa'
$ echo '    aaaaa   ' | grep -G 'bbbbb|aaaaa'
$ echo '    aaaaa   ' | grep -E 'bbbbb|aaaaa'
    aaaaa

两个都grepsed参考重新格式化 (7)其中明确指出:

过时的(“基本”)正则表达式在几个方面有所不同。 `|'是一个普通字符,没有与其功能相当的字符。

但看起来,如果我们“逃离管道”,那么我们确实获得了功能。那肯定有味道。此外,该球场最近似乎出现了破损 - 请参阅regex(3): 添加测试以覆盖最近的 BRE 回归

似乎有一些工作可以取代正则表达式在 libc 中。

正如查尔斯·达菲(Charles Duffy)在下面评论的那样

因为某些工具实现了非标准扩展,其中您可以使用反斜杠在 BRE 上下文中获得仅 ERE 的行为

我已经习惯了 FreeBSD 的非常好的文档。这意味着我不确定这是否是有意为之但没有记录 - 或者是破损。

相关内容