这两者有什么区别吗。
[[ $a == z* ]]
和
[ $a == z* ]
我可以举个例子,说明它们会有不同的输出吗?
此外, 的工作方式[[ ]]
与 有何不同[ ]
?
答案1
[[ … ]]
和之间的区别[ … ]
主要体现在为什么不带引号的空格参数扩展在双括号“[[”内有效,但在单括号“[”内无效?。至关重要的是,[[ … ]]
是特殊的语法,而[
是命令的一个看起来很有趣的名称。[[ … ]]
对于里面的内容有特殊的语法规则,[ … ]
没有。
添加了通配符后,[[ $a == z* ]]
计算方式如下:
- 解析命令:这是
[[ … ]]
围绕条件表达式的条件构造$a == z*
。 - 解析条件表达式:这是
==
二元运算符,操作数为$a
和z*
。 - 将第一个操作数展开为变量的值
a
。 - 评估
==
运算符:测试变量的值是否a
与模式匹配z*
。 - 计算条件表达式:其结果是条件运算符的结果。
- 现在对命令进行求值,如果条件表达式为真,则其状态为 0,如果条件表达式为假,则其状态为 1。
[ $a == z* ]
评估方式如下:
- 解析命令:这是
[
带有通过评估单词$a
,==
,z*
,形成的参数的命令]
。 - 展开
$a
为变量的值a
。 - 对命令的参数执行分词和文件名生成。
- 例如,如果 的值为
a
6个字符的字符串foo b*
(通过eg获得a='foo b*'
),当前目录下的文件列表为(bar
,baz
,qux
,zim
,zum
),则扩展的结果为以下单词列表:[
,foo
,bar
,,,,,, .baz
==
zim
zum
]
- 例如,如果 的值为
[
使用上一步中获取的参数 运行该命令。- 对于上面的示例值,该
[
命令抱怨语法错误并返回状态 2。
- 对于上面的示例值,该
注意:在 中[[ $a == z* ]]
,在步骤 3 中, 的值a
不会进行分词和文件名生成,因为它位于需要单个单词的上下文中(条件运算符 的左侧参数==
)。在大多数情况下,如果单个单词在该位置有意义,则变量扩展的行为就像在双引号中一样。但是,该规则有一个例外:在 中[[ abc == $a ]]
,如果 的值a
包含通配符,则将abc
与通配符模式进行匹配。例如,如果a
is的值a*
则为[[ abc == $a ]]
true (因为通配符*
来自带引号的扩展$a
matches bc
),而值为 false (因为来自带引号的扩展的[[ abc == "$a" ]]
普通字符不 match )。在里面,双引号没有什么区别,*
$a
bc
[[ … ]]
除了字符串匹配运算符的右侧(=
,==
,!=
和=~
)。
答案2
[
是命令的别名test
。 Unix 版本 6 有一个if
命令,但版本 7(1979)附带了新的伯恩外壳那有几个编程构造包括 if-then-else-elif-fi 构造,并且 Unix 版本 7 添加了test
if
该命令执行了旧版本中该命令执行的大部分“测试” 。
[
被用作别名test
,并且两者都被内置到 Unix System III (1981) 的 shell 中。尽管应该指出的是,一些 Unix 变体[
直到很久之后才具有命令(直到 2000 年代初期,一些 BSD 上都sh
基于 Almquist shell(test
内置函数始终包含在ash
的源代码中,但在这些 BSD 上它最初被禁用))。
请注意,test
aka[
是执行“测试”的命令,该命令没有执行任何赋值操作,因此没有理由消除赋值运算符和相等运算符之间的歧义,因此相等运算符是=
。==
仅受最近的一些实现支持[
(并且只是 的别名=
)。
因为[
只不过是一个命令,所以 shell 解析它的方式与任何其他命令相同。
具体来说,在您的示例中,$a
,因为它没有被引用,所以会根据通常的单词分割规则被分割成几个单词,并且每个单词都会经历文件名生成(又名通配)以产生可能更多的单词,每个单词都会产生命令的单独参数[
。
同样,z*
将扩展到当前目录中以z
.
例如,如果$a
是,并且当前目录中b* = x
有z1
、z2
、b1
和文件,则该命令将获得 9 个参数:、、、、、、、和。b2
[
[
b1
b2
=
x
==
z1
z2
]
[
将其参数解析为条件表达式。这 9 个参数加起来不构成有效的条件表达式,因此它可能会返回错误。
该[[ ... ]]
构造可能是在 1988 年左右由 Korn shell 引入的,如下所示:ksh86a
1987年没有,而ksh88
从一开始就有。
除了 ksh(所有实现)之外,[[...]]
bash(自版本 2.02 起)和 zsh 也支持,但这三个实现都是不同的,并且同一 shell 的每个版本之间也存在差异,尽管这些更改通常是向后兼容的(一个值得注意的例外是 bash 的=~
已知在某个版本之后当其行为发生变化时会破坏一些脚本)。[[...]]
POSIX、Unix 或 Linux (LSB) 未指定。曾多次考虑将其包含在内,但由于主要 shell 支持的通用功能已被命令[
和case-in-esac
构造所涵盖,因此未包含在内。
整个[[ ... ]]
结构构成了一个命令。也就是说,它有一个退出状态(这是它最重要的资产,因为它是评估条件表达式的结果),您可以将其通过管道传输到另一个命令(尽管它没有用),并且通常在任何需要的地方使用它使用任何其他命令(仅在 shell 内部,因为它是 shell 构造),但它不会像普通的简单命令一样被解析。里面的内容被解析了通过外壳作为条件表达式,分词和文件名生成的常用规则应用不同。
[[ ... ]]
从一开始就知道==
并且相当于=
1。 ksh 的一个错误(并且导致混乱和许多错误)是=
and==
不是一个相等运算符,而是一个模式匹配运算符(尽管匹配方面可以通过引用来禁用,但规则不明确,不同外壳程序有所不同)。
在上面的代码中[[ $a == z* ]]
,shell 会将其解析为与通常规则类似的规则中的几个标记,将其识别为模式匹配比较,将其视为z*
与变量内容匹配的模式a
。
[[ ... ]]
一般来说,搬起石头砸自己的脚比用命令更难[
。但有一些规则,比如
- 总是引用变量
- 切勿使用
-a
or-o
运算符(使用多个[
命令和&&
and||
壳运营商)
[
使用 POSIX shell提高可靠性。
[[...]]
在不同的 shell 中支持额外的运算符,例如-nt
、 regexp 匹配运算符...但列表和行为因 shell 和版本而异。
因此,除非您知道您的脚本将被解释的 shell 及其最低版本,否则坚持使用标准[
命令可能更安全。
1一个例外:[[...]]
在版本 中添加到 bash 中2.02
。直到2.03
更改为止,[[ x = '?' ]]
将返回 true,而[[ x == '?' ]]
将返回 false。也就是说,=
在这些版本中使用运算符时,引用不会阻止模式匹配,但在使用==
.
答案3
两者都用于计算表达式,[[ 不适用于 POSIX 较旧的 bourn shell,[[ 还支持模式匹配和正则表达式。例子试试这些
[ $n -eq 0 -a $y -eq 0 ] && echo "Error" || echo "Ok"
[[ $n -eq 0 && $y -eq 0 ]] && echo "Error" || echo "Ok"