看来,例如
cat sed_data.txt | sed 's/\b[0-9]\{3\}\b/NUMBER/g'
,我必须转义字符以形成正则表达式。在这种情况下,我不得不使用花括号来进行多次解释。
为什么?我期望除非逃脱,否则一切都会是正则表达式字符。即相反。
s/regex//g
已经需要一个正则表达式,我会想到它是需要文本逃脱
看来,例如
cat sed_data.txt | sed 's/\b[0-9]\{3\}\b/NUMBER/g'
,我必须转义字符以形成正则表达式。在这种情况下,我不得不使用花括号来进行多次解释。
为什么?我期望除非逃脱,否则一切都会是正则表达式字符。即相反。
s/regex//g
已经需要一个正则表达式,我会想到它是需要文本逃脱
Answers:
这是因为sed
使用POSIX BRE(基本正则表达式)而不是您可能习惯于Perl或朋友使用的ERE(扩展正则表达式)。
从sed(1)
手册页:
REGULAR EXPRESSIONS
POSIX.2 BREs should be supported, but they aren't completely because of
performance problems. The \n sequence in a regular expression matches
the newline character, and similarly for \a, \t, and other sequences.
以上链接的相关报价:
基本正则表达式或BRE风格对一种风格进行了标准化,该风格类似于传统UNIX grep命令所使用的一种。这几乎是当今仍在使用的最古老的正则表达式。使这种风味与众不同的一件事是,大多数元字符都需要反斜杠才能赋予其元字符自己的风味。包括POSIX ERE在内的大多数其他风味都使用反斜杠来抑制元字符的含义。
引用了克雷格·桑德斯的评论的逐字记录:
请注意,至少在GNU sed中,您可以通过-r或--regexp-extended命令行选项告诉sed使用扩展的正则表达式。如果您要避免过度转义来使sed脚本丑陋,这很有用。
-r
或--regexp-extended
命令行选项告诉sed使用扩展的正则表达式。如果您要避免过度转义来使sed脚本丑陋,这很有用。
sed
实现(当它们确实支持ERE,主要是BSD时)倾向于-E
代替它使用(这更有意义,因为这与for相同grep
。为什么GNU sed
选择-r
对我来说是个谜)。
那是出于历史原因。
Regexp ed
在70年代初期首次在Unix中通过实用程序引入。虽然ed
是基于qed
其实现由同一作者了解更复杂的正则表达式,ed
只有理解^
,$
,[...]
,.
,*
和\
逃跑上述所有。
现在,当需要更多运营商时,必须找到一种在不破坏向后兼容性的情况下引入它们的方法。如果脚本用于将s
ed
命令s/foo() {/foo (var) {/g
替换为foo() {
with的所有实例,foo(var) {
并且您引入了(
or {
运算符,则该脚本将中断。
但是,没有脚本会这样做s/foo\(\) {/foo\(var\) {/
,因为这与RE运算符相同,s/foo() {/foo(var) {/
并且没有理由逃脱,(
因为那不是RE运算符。因此,引入new \(
或\{
operator不会破坏向后兼容性,因为使用较旧的语法不太可能破坏现有脚本。
就是这样。后来,\(...\)
最初只为s
ed
命令添加了类似的功能s/foo\(.\)/\1bar/
,后来又添加了grep '\(.\)\1'
(但不允许添加\(xx\)*
)。
在UnixV7(1979年,大约十年后)中,在新功能egrep
和awk
实用程序中添加了一种新形式的正则表达式,称为扩展正则表达式(由于它们是新工具,因此不会破坏向后兼容性)。最后,它提供了Ken Thompson的古代版本qed
(alternation运算符|
,grouping (..)*
)中可用的功能,并添加了一些运算符,例如+
and ?
(但不具有基本正则表达式的backref功能)。
后来BSD系统添加\<
和\>
(既BRE和ERE),和SysV添加\{
和\}
只BREs里面。
直到如此晚才被添加到ERE,并通过这种向后兼容{
而}
被添加到ERE。并非所有人都添加了它。例如,除非强制进入POSIX一致性模式,否则awk
不支持GNU 4.0.0(2011)版{
。
当GNU grep
写于90年代初,这添加了所有来自BSD和SysV的东西(如\<
,{
),并代替具有用于BRE和ERE两个单独的regexp语法和发动机,实现了相同的运营商两者,只的BRE同行(
,?
,{
,+
必须用一个反斜杠(以与其他实施方式BRE兼容)。这就是为什么您可以.\+
在GNU中进行操作grep
(尽管它不是POSIX或不受其他实现支持),而您却可以(.)\1
在GNU中进行egrep
(尽管它不是POSIX或不受许多其他实现(包括GNU awk
)支持)。
添加\x
运算符不是以向后兼容的方式添加更多运算符的唯一方法。例如,perl
使用了(?...)
。仍然与ERE向后兼容,因为(?=...)
在ERE中无效.*?
。vim
对于类似的运营商,通过引入\@=
或.\{-}
例如,做了不同的选择。