[ ... ] 和 [[ ... ]] 之间的相等性测试存在差异。
[ ... ] 是test 命令的别名:
STRING1 = STRING2 字符串相等
但是,当使用[[ ... ]]
当使用== 和!= 运算符时,运算符右侧的字符串被视为一个模式,并根据下面模式匹配中描述的规则进行匹配。如果启用了 shell 选项 nocasematch,则执行匹配时不考虑字母字符的大小写。如果字符串匹配 (==) 或不匹配 (!=) 模式,则返回值为 0,否则为 1。可以引用模式的任何部分以强制将其作为字符串匹配。
= 符号似乎也是如此:
$ foo=bar
$ if [[ $foo = *ar ]]
> then
> echo "These patterns match"
> else
> echo "These two strings aren't equal"
> fi
These patterns match
注意区别:
$ foo=bar
> if [ $foo = *ar ]
> then
> echo "These patterns match"
> else
> echo "These two strings aren't equal"
> fi
These two strings aren't equal
但是,[ $f00 = *ar ] 语法存在一些陷阱。这与以下内容相同:
test $foo = *ar
这意味着 shell 将在执行语句之前插入 glob 表达式和变量。如果$foo 为空,则命令将变为:
test = *ar # or [ = *ar ]
由于= 不是test 中的有效比较运算符,您将收到如下错误:
bash: [: =: unary operator expected
这意味着[ 期望在test 手册页中找到一个参数。
而且,如果我的目录中碰巧有一个文件bar,shell 会将*ar 替换为与该模式匹配的所有文件(在本例中为bar),因此命令将变为:
[ $foo = bar ]
这是真的。
要解决[ ... ] 的各种问题,您应该始终在参数周围加上引号。这将防止 shell 对 glob 进行插值,并有助于处理没有值的变量:
[ "$foo" = "*ar" ]
这将测试变量$foo 是否等于字符串*ar。即使$foo 为空,它也会起作用,因为引号将强制进行空字符串比较。 *ar 周围的引号将阻止 shell 插入 glob。这是一个真正的平等。
当然,如果你在使用[[ ... ]]时使用引号,你也会强制匹配字符串:
foo=bar
if [[ $foo == "*ar" ]]
then
echo "This is a pattern match"
else
echo "These strings don't match"
fi
所以,最后,如果你想测试字符串是否相等,你可以使用[ ... ] 或[[ ... ]],但你必须引用你的参数。如果要进行 glob 模式匹配,则必须去掉引号,并使用 [[ ... ]]。