没有充分的理由
[[ $a = a|b ]]
应该报告错误而不是测试$ a是否为a|b字符串,而[[ $a =~ a|b ]]不会返回错误。
唯一的原因是|通常(外部和内部[[ ... ]])一个特殊字符。在该[[ $a =位置,bash期望的令牌类型是普通WORD,例如普通Shell命令行中的参数或重定向目标(但好像extglob自bash 4.1起已启用该选项)。
(在这里用WORD来表示,是指假设的shell语法中的一个词,如POSIX规范所描述的那样,即shell将在简单的shell命令行中将其解析为一个标记,而不是像英语这样的单词的其他定义字母序列或非间距字符序列中的一个foo"bar baz"($(echo x y),)是两个这样的WORD。
在普通的shell命令行中:
echo a|b
被echo a输送到b。a|b不是WORD,而是三个令牌:a WORD,|令牌和b WORD令牌。
在中使用时[[ $a = a|b ]],bash期望得到一个()的WORDa,但随后发现一个|导致错误的意外令牌。
有趣的是,bash不要抱怨:
[[ $a = a||b ]]
由于它现在是a一个||标记,后面是b,后面是,因此其解析方式与:
[[ $a = a || b ]]
正在测试的$a是a或该b字符串为非空。
现在,在:
[[ $a =~ a|b ]]
bash不能具有相同的解析规则。具有相同的解析规则将意味着以上内容将产生错误,并且需要引用该内容|以确保a|b是单个WORD。但是,从bash 3.2开始,如果您这样做:
[[ $a =~ 'a|b' ]]
与a|bregexp 不再匹配,而是与a\|bregexp 匹配。也就是说,shell引用具有消除regexp运算符特殊含义的副作用。这是一项功能,因此其行为与之类似[[ $a = "?" ]],但是通配符模式(用于[[ $a = pattern ]])是shell WORDS(例如,用于glob),而正则表达式则不是。
因此,在解析运算符的参数时,必须以不同的bash方式对待所有扩展的正则表达式运算符,否则这些运算符通常是特殊的外壳字符,如|,。()=~
不过,请注意
[[ $a =~ (ab)*c ]]
现在可以了,
[[ $a =~ [)}] ]]
没有。你需要:
[[ $a =~ [\)}] ]]
[[ $a =~ [')'}] ]]
在先前版本中的哪个bash会在反斜杠上错误地匹配。那是固定的,但是
[[ $a =~ [^]')'] ]]
难道不是像它应该例如匹配反斜线。由于bash未能意识到该)内容在方括号内,因此对)进行转义以[^]\)]生成与],\和上任何字符都匹配的正则表达式)。
ksh93 在这方面有更严重的错误。
在中zsh,这是一个正常的shell字词,用引号regexp运算符不会影响regexp运算符的含义。
[[ $a =~ 'a|b' ]]
与正则a|b表达式匹配。
这意味着=~也可以将其添加到[/ test命令中:
[ "$a" '=~' 'a|b' ]
test "$a" '=~' 'a|b'
(也可以在中使用yash。=~需要zsh作为=something特殊的shell运算符引用在其中)。
bash 3.1以前的表现就好zsh。它在3.2中进行了更改,大概是与对齐的ksh93(即使bash是第一个出现的shell [[ =~ ]]),但是您仍然可以这样做BASH_COMPAT=31或shopt -s compat31还原为以前的行为(除了[[ $a =~ a|b ]]在bash3.1中返回错误时,它不再存在了)的bash -O compat31新版本中bash)。
希望它能弄清为什么我说规则令人困惑以及为什么使用:
[[ $a =~ $var ]]
有助于包括与其他shell的可移植性。
|是特殊的)是默认在右手边[[ $var = $pattern ]]。隔离shopt出现此行为的版本和选项配置会很有趣-如果只是extglob默认情况下或显式配置启用的版本和选项配置,那么就可以了。