我在某处读到过,在 shell 脚本中,[..]
像例如这样的构造[ -e $HOME/temp ]
符合 POSIX 标准。而[[..]]
像这样的脚本构造[[ -e $HOME/temp ]]
则不符合。
这是真的吗?
除了符合 POSIX 规范之外,[..] 是否比 [[..]] 具有其他固有优势?反之亦然?
我在某处读到过,在 shell 脚本中,[..]
像例如这样的构造[ -e $HOME/temp ]
符合 POSIX 标准。而[[..]]
像这样的脚本构造[[ -e $HOME/temp ]]
则不符合。
这是真的吗?
除了符合 POSIX 规范之外,[..] 是否比 [[..]] 具有其他固有优势?反之亦然?
是的,该
[
实用程序也称为test
标准,您可以在 OpenGroup 网站上找到其 POSIX 2024 规范的 HTML 版本。曾经有一个提案要求用 POSIX语言来指定 ksh
[[...]]
sh
,但是最终被否决了(缩减为仅添加一些在[
大多数实现中常见的额外操作符)。您会看到理由部分指出:
[[...]]
和之间的一些相关区别[
:[[...]]
比使用 with更容易[...]
(其中-a
/-o
操作符实际上已被弃用,因为它们无法可靠地使用),但使用 using[ ... ] && [ ... ] || [ ... ]
很好并且不会产生惩罚,因为[
它总是内置的,这使得[[...]]
自己的&&
/变得多余(并且可能会造成混淆,因为优先规则与shell的/||
不同)。&&
||
[[ $string = $pattern ]]
实际上进行的是模式匹配而不是相等性比较。这对于标准构造来说也是多余的case
,也是错误的来源,因为人们往往认为在内部不加引号的变量是可以的(而且通常都是这样),但在比较字符串相等性时却[[...]]
忘记了这样做。[[ $string1 = "$string2" ]]
[[ $string =~ $pattern ]]
因为根据 shell 的不同,其执行方式也不同。bash 和其他一些 shell 做出了一个不幸的决定,让引用影响那里的正则表达式操作,这是错误的,因为正则表达式语法与正常的 shell 标记化不兼容(更多详细信息请参阅如何将正则表达式存储在 shell 变量中以避免引用 shell 特有的字符的问题?以及上面提到的 Austin Group 错误)。zsh[
和 yash 的内置命令=~
也有一个运算符。[[...]]
将其操作数解释为算术表达式(这在大多数 shell 中会导致[[ $1 -eq $2 ]]
命令注入漏洞(并且当数字以 0 开头时会引起意外,这会导致它们在某些 shell 中被解释为八进制)。而 POSIX 要求的操作数[
被视为十进制整数。[[...]]
特定于构造并且因 shell 而异,而[
只是一个简单的命令,因此可以像任何其他命令一样处理。所以
[
通常都没问题,引用 POSIX 的话,真正的问题是test
命令 ([
)的误用。只要您记得引用变量和其他扩展(所有命令都需要,而不仅仅是
[
)并且不使用-a
(and),-o
(or)弃用的二元运算符((...)
一旦您不能组合多个测试,就不需要它们),[
就可以了(在进行数字比较时更安全)。[[...]]
可以更好,因为它可以使代码更短,可以允许人们跳过引用一些扩展,但这主要是语法糖,但是代价是必须学习额外的语法及其怪癖。