最近我在用正则表达式做一些家庭作业时遇到了以下情况。
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]