在 egrep 中使用 "[ ]" 时获得奇特的结果,尽管 Linux 中使用了""(转义序列)



最近我在用正则表达式做一些家庭作业时遇到了以下情况。

s@ubuntu:~$ echo b | egrep []b]
b
s@ubuntu:~$ echo b | egrep [[b]
b
s@ubuntu:~$ echo b | egrep []b[]
b
s@ubuntu:~$ echo b | egrep [b[]
b
s@ubuntu:~$ echo b | egrep [[b]]
s@ubuntu:~$ echo b | egrep [b]]
s@ubuntu:~$ echo b | egrep [b]]
s@ubuntu:~$ echo b | egrep [b\]]
s@ubuntu:~$ echo b | egrep [[b]]

为什么我在最后5个案例中没有打印"b"?

  • egrep [[b]]—查找后面跟有]b[;找不到
  • egrep [b]]—查找后面跟着]b;找不到
  • egrep [b]]—查找后面跟着]b;找不到。反斜杠被shell省略,egrep看不到
  • egrep [b\]]—查找b或后面跟着]的反斜杠;找不到
  • egrep [[b]]—查找b或后面跟有][;找不到。反斜杠被shell省略,egrep看不到

在字符类(由[启动)内,第一个]终止该类,除非][之后的第一个字符,或者对于否定的字符类是[^之后的第一字符。注意,]不是regex元字符,除非前面有一个[使其成为字符类的末尾。您还发现,$不是字符串中间的元字符,^也不是,除非它出现在开头,*+?也不是,如果它们首先出现,等等。有关详细讨论,请参阅POSIX正则表达式-egrep(现在的grep -E)处理的正则表达式是"扩展正则表达式"。

egrep有机会看到反斜杠之前,shell会乱插反斜杠。您应该将regex用单引号括起来,以避免shell更改egrep所看到的内容。

你可以通过改变回应的内容来证明我的分析:

echo '[b]' | egrep [[b]]
echo '[b]' | egrep [b]]
echo '[b]' | egrep [b]]
echo '[b]' | egrep [b\]]
echo '[b]' | egrep [[b]]

其输出为:

[b]
[b]
[b]
[b]
[b]

这些实例中的[(在回显数据中)是由于外观原因而存在的;它可以被省略并且这些行将被接受。

原因在于括号表达式中应用的特殊规则:

右方括号CCD_ 37必须紧接在开口CCD_ 38或CCD_。

转义字符实际上在字符类[...]中进行处理

在成瘾中,shell在将表达式传递给egrep之前应用转义符,因为正则表达式周围缺少单'...'或双引号"..."

Jonathan Leffler用例子很好地解释了这一点,我只能在括号内报告Posix扩展规则的链接,以添加概述:

http://pubs.opengroup.org/onlinepubs/007904875/basedefs/xbd_chap09.html#tag_09_03_05

更新

带引号的相同表达式:

# this matches 'b]' or ']'
~$ echo b] | egrep '[b]]'
b]
~$ echo ']' | egrep '[b]]' # note the quotes prior and after the pipe
]
# the next one is equivalent to '[b]]' 
# cause a double  inside chars class is redundant
~$ echo b] | egrep '[b\]]'
b]
~$ echo ']' | egrep '[b\]]'
]
# the last one matches ']' or '[]' or 'b]'
~$ echo b] | egrep '[[b]]'
[b]
~$ echo [] | egrep '[[b]]'
[]
~$ echo ']' | egrep '[[b]]'
]
# without quotes in the echo section, the escape  is applied by the shell
# so egrep receive only a closing bracket ']' and nothing is printed out
~$ echo ] | egrep '[[b]]'
# If we remove instead the quotes from the egrep section 
# the regex becomes equivalent to [[b]] so it now matches '[]' or 'b]' and not ']' anymore
~$ echo ']' | egrep [[b]]
~$ echo '[]' | egrep [[b]]
[] 
~$ echo 'b]' | egrep [[b]]
b]

相关内容

最新更新