最近我在使用正则表达式做家务时遇到了以下情况。
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\]]
为什么我没有得到' b'最近5个案例?
答案 0 :(得分:5)
egrep [[b]]
- 查找b
或[
后跟]
;没找到。egrep [b]]
- 查找b
后跟]
;没找到。egrep [b\]]
- 查找b
后跟]
;未找到。 shell省略了反斜杠,但egrep
没有看到。egrep [b\\]]
- 查找b
或反斜杠后跟]
;没找到。egrep [\[b\]]
- 查找b
或[
后跟]
;未找到。 shell省略了反斜杠,但egrep
没有看到。在一个字符类(由[
开始)中,第一个]
终止该类,除非]
是[
之后的第一个字符,或第一个字符在[^
之后为一个否定的字符类。请注意,]
不是正则表达式元字符,除非前面有[
使其成为字符类的末尾。您还发现$
不是字符串中间的元字符,也不是^
,除非它出现在开头,*
也不+
也不?
如果它们首先出现,等等。请参阅POSIX Regular Expressions进行详细讨论 - egrep
(现在grep -E
)处理的正则表达式是“扩展正则表达式”。
在egrep
有机会看到它们之前,shell会出现反斜杠。您应该将正则表达式用单引号括起来,以避免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]
这些例子中的[
(在回音数据中)出于美观的原因而存在;它可以省略,并且可以接受这些行。
答案 1 :(得分:3)
原因在于括号表达式中应用的特殊规则:
右侧方括号
]
必须在开场[
或[^
后立即放置,以作为文字对待。
和
在字符集
中逐字处理转义字符\
[...]
在成瘾中,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]