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