本文介绍了Linuxbash的test命令、[命令、[[命令的用法以及它们之间的区别。[命令在bash中,[关键字本身就是一个命令,它不是if命令的一部分。有关说明,请参阅帮助[:[:[arg...]评估条件表达式。这是内置“test”的同义词,但最后一个参数必须是文字“]”,以匹配开头的“[”。也就是说,[命令用于评估条件表达式。该命令是test命令的同义词,其对条件表达式的判断结果与test命令完全相同。但是[命令要求命令的最后一个参数必须是]],好像是关闭方括号的效果。在实际使用中,test命令和[命令经常与if命令和while命令结合使用,但这不是必须的。test命令和[命令本身独立于if命令和while命令,可以独立执行。后面会用到test命令来说明具体的用法,这些说明都适用于[命令。注意:]本身不是bash命令,它只是[命令需要的一个参数,而且必须是最后一个参数。在使用[命令时,最大的错误就是没有在这个命令后面加一个空格。例如,[string1=string2]是错误的。时刻注意[本身就是一个命令,命令名是[。该命令后面必须跟一些参数,命令名和参数之间必须用空格隔开。[string1这种写法实际上会执行名为[string1的命令,而不是[命令。同样,]本身就是一个参数,也需要用空格来分隔其他参数。string2]其实是一个名为“string2]”的参数,不是string2和]两个参数。test命令在bash中,您可以使用test内置命令来评估条件表达式。检查manbash中对测试命令的描述如下:test:test[expr]Evaluateconditionalexpression。退出状态为0(真)或1(假),具体取决于EXPR的评估。测试的行为取决于参数的数量。阅读bash手册页以获得完整的规范。这个描述提到了测试命令的参数数量会影响它的行为。具体可以参考manbash的说明。不同数量的参数会导致测试命令返回很多意想不到的结果,这是非常关键的一点。上面我们介绍比较字符串的条件表达式的时候已经提到了。可以在bash-string.md文件中找到详细说明。test命令支持manbash的CONDITIONALEXPRESSIONS部分提到的所有条件表达式,支持以下运算符组合条件表达式,运算符的优先级从高到低排列:operatormeaning!exprifexpr条件表达式如果公式为假,那么!exprreturnstrue(expr)返回expr条件表达式的值expr1-aexpr2当expr1和expr2条件表达式都为真时,整个表达式为真expr1-oexpr2当expr1或expr2条件表达式中有一个表达式为true,整个表达式都是true。可以看出,测试命令使用-a运算符进行AND运算,使用-o运算符进行OR运算。||等运算符不支持&&。这些运算符用于组合条件表达式,它们的优先级低于条件表达式本身的运算符。注意:在测试命令中,每个运算符(operator)和每个运算符参数(operand)必须用空格隔开。上面的例子说明了条件表达式运算符需要加空格的情况。还必须在!、(,)、-a和-o运算符前后添加空格。另外,在bash中,括号有特殊的含义,(cmd)表示启动一个子shell来执行cmd命令。所以这里的(和)需要使用\转义字符,或者引号来去掉它们的特殊含义,以免被当作命令替换(Commandsubstitution)。具体例子如下:$test!a==b-bash:!a:eventnotfound$test!一个==乙;echo$?0$测试(a==b);echo$?-bash:意外标记'a'$测试附近出现语法错误(a==b);echo$?-bash:意外标记'a'$测试\(a==a\)附近出现语法错误;echo$?1$测试\(a==a\);echo$?0$test'('a==a')';echo$?0$测试'(a==a)';echo$?0$测试'||'b-bash:test:||:binaryoperatorexpected可以看到,命令test!a==b报错,!之间没有空格。和字符a,它被视为对历史命令的引用。考试!a==b命令返回0。!的优先级这里的运算符低于==运算符。先对a==b条件表达式进行判断,然后对a==b条件表达式的判断结果取反,不报错。test(a==b)命令虽然在每个运算符和运算符参数之间添加了空格,但没有转义或引号(and),导致它被当成命令替换,执行时报错。test(a==b)命令也将括号视为命令替换,并在执行时报告错误。test\(a==a\)命令没有执行错误,括号用\转义了,不会被当做命令替换,但是返回值为1。看来以为a是相等的toa是假的,这是错误的。该命令实际上是比较“(a”字符串是否等于“a)”字符串。两个字符串显然不相等,所以返回为1.test\(a==a\)命令在\(和\)之间,前后加空格才是正确的写法,如果判断a等于a,为真,返回值为0。test'('a==a')'命令用单引号括起来,括号不会被当做命令替换,可以正常执行。如果有多个字符需要转义,可以将整个表达式用引号括起来。由于引号内的特殊字符,大部分都失去了特殊意义,所以没有必要对它们进行转义。这就是test'(a==a)'命令的用法。测试一个'||'b命令报错,说明||不是有效的运算符,测试命令不支持此类运算符。在test命令中,如果要进行算术运算,需要使用$((expression))进行算术运算并获取运算结果。直接写算术运算表达式会报错。原因是bash默认不把-和+这两个字符当作减号和加号,它们只是普通的字符参数。-通常用于指定命令选项。((expression))表达式中必须使用-和+两个字符来执行算术运算。使用$((expression))获取运算结果。具体例子如下:$count=4$test$count-2-eq2-bash:test:toomanyarguments$test$count+2-ne2-bash:test:toomanyarguments$test$(($count-2))-eq2;echo$?0可以看到test$count-2-eq2命令和test$count+2-ne2命令都执行了,报错,说明提供的参数个数过多。这里的-和+都作为字符参数传递给测试命令。但是这个命令并没有把这两个字符当作减号或者加号,不进行算术运算,最后报错。test$(($count-2))-eq2命令可以得到count变量的值,减去2,得到本次算术运算的结果,与整数2比较,最后返回0。[[命令在bash中,您可以使用[[复合命令来评估条件表达式。查看manbash对[[命令的描述如下:[[expression]]根据条件表达式expression的评估返回状态0或1。表达式由下面条件表达式中描述的基本要素组成。不对[[和]]之间的单词执行单词拆分和路径名扩展;执行波浪号扩展、参数和变量扩展、算术扩展、命令替换、进程替换和引用删除。请参阅test内置命令的描述(下面的SHELLBUILTINCOMMANDS部分)以了解参数的处理(即缺少参数)。即[[命令支持manbash的CONDITIONALEXPRESSIONS部分提到的所有条件表达式,不同参数个数的判断结果与test命令一致。test命令不同参数个数的处理,请参考bash-string.md文件的说明。[[命令后必须跟]]命令,两个命令之间必须用空格隔开。]]本身就是一个命令。在这两个命令之间,不执行分词和路径名扩展。不分词是指在获取字符串变量的值时,即使字符串中间有空格,也不会被拆分成多个字符串。具体例子如下:$value="teststring"$[[-n$value]];echo$?0$test-n$value-bash:test:test:预期二元运算符$[[-n"teststring"]];echo$?0$[[-nteststring]]-bash:syntaxerrorinconditionalexpression-bash:syntaxerrornear'string'可以看到value变量对应的字符串有空格,[[-n$value]]命令可以正确判断value的变量值不是空串,不对变量值进行分词。test-n$value命令执行会报错,value变量value有空格,$value分词后会变成两个字符串参数。报告错误是因为-n运算符不希望后面有多个参数。[[-n"teststring"]]命令也可以正常执行,"teststring"为字符串参数。但是,[[-nteststring]]命令会报错。这种写法是手动分词,“test”和“string”会被当成两个字符串参数。在bash中,如果在获取字符串变量的值时没有将变量值用双引号引起来,往往会因为变量值为空或者变量值中包含空格而导致分词,导致意想不到的结果。大多数情况下,建议用双引号将变量值括起来。为了保持写法一致,虽然[[命令不进行分词,但还是建议用双引号将变量值括起来。没有路径名扩展意味着*,?,[...]通配符不会扩展为当前目录中的文件名,但这些字符将保持不变。这些通配符只能在某些运算符中用于模式匹配。前面提到,当[[命令使用==、=、!=运算符时,运算符右侧的字符串可以使用*、?、[...]通配符进行模式匹配。在[[和]]内会进行算术展开,不需要用$((expression))获取运算结果,直接写成算术表达式即可,但整个之间不能有空格算术表达式。如果要在算术表达式之间加空格,还是需要用$((expression))来展开。具体例子如下:$count=4$[[$count-2-eq2]]-bash:conditionalbinaryoperatorexpected-bash:syntaxerrornear'-'$[[$count-2-eq2]];echo$?0$[[$(($count-2))-eq2]];echo$?0可以看到[[$count-2-eq2]]命令执行报错。[[$count-2-eq2]]命令可以正常执行。这里$count-2会做算术运算。[[$(($count-2))-eq2]]该命令使用$(())进行算术展开,$count、-、2之间可以加空格,不会报错。当[[命令使用==、=、!=运算符时,运算符右侧的字符串可以使用bash通配符进行模式匹配。此外,[[命令还支持=~运算符。运算符右边的字符串可以使用扩展的正则表达式作为模式串来判断左边的字符串是否包含右边的模式串。注意是包含关系,不是完全匹配,即判断右边的模式是否是左边字符串的子串,而不是判断右边的模式是否完全等于字符串在左侧。由于bash通配符和扩展正则表达式中的一些特殊字符是同一个字符,但具体含义不同,所以要注意区分两种情况,并使用正确的写法。具体例子如下:$[[main.c==*.c]];echo$?0$[[main.c=~*.c]];echo$?2可以看出,[[main.c==*.c]]命令返回0,判断左边的字符串以.c结尾。这种写法可以用来判断一个文件名后缀是否为.c。但是[[main.c=~*.c]]命令返回2,报错,右边的扩展正则表达式无效。在扩展正则表达式中,*不能出现在表达式的开头。注意:在==、=、!=、=~运算符中,运算符右侧的字符串可以使用特殊字符来匹配特定的模式,但这些特殊字符不能用引号引起来。这些特殊字符在引号内失去了特殊意义,只能匹配字符本身。[[命令的AND或NOT运算符[[命令支持以下运算符组合条件表达式,运算符的优先级从高到低排列:运算符含义(expr)返回expr条件表达式的值!expr如果expr条件表达式为假,那么!expr返回真expr1&&expr2当expr1和expr2条件表达式都为真时,整个表达式为真|表达式1||表达式2|当expr1或expr2条件表达式为真时,整个表达式为真|可以看到[[命令使用&&运算符进行AND运算,使用||operator进行OR运算,不支持test命令的-a和-o运算符。(,),&&,||前后不需要加空格运算符,无需使用\进行转义。但是,在!前后仍然需要空格。操作员。一个例子如下:$[[!a==b]]-bash:!a:eventnotfound$[[(a==a)]];echo$?0$[[a!=b&&a!=c]];echo$?0$[[a!=b||a==a]];回声$?0$[[1<2]];echo$?0可以看到,[[!a==b]]command执行命令,!之间没有空格运算符和字符a。[[(a==b)]]命令不报错,判断结果正确。(,)不需要用\转义,括号前后也不需要加空格。[[a!=b&&a!=c]]命令在&&运算符前后不加空格,不报错。[[a!=b||a==a]]命令类似。[[1<2]]命令不会执行错误,也不需要用\转义<。测试命令需要用\转义<。注意:Bash本身,其他命令也支持&&、||运营商。一般来说,它也分别对应于逻辑与和逻辑或。由于含义相似,在某些情况下可能会混淆。在实际执行命令时,一定要区分哪个命令处理了&&和||运算符,并根据相应命令的规则了解这些运算符的作用,避免出现意想不到的结果。test、[、[[命令的区别下面介绍test、[、[[这三个命令的区别。test和[命令的区别[command是test命令的同义词,大部分用法是一样的。唯一明显的区别是[命令要求最后一个参数必须是]。test命令没有这个要求,也不能处理]参数。下面将以[命令为例,说明与[[命令的区别。[和[[命令之间的区别。[命令和[[命令都可以用来计算条件表达式。具体使用上有一些区别。具体对比如下:特点[command[[commandPOSIXstandardPOSIXstandardcommand不是标准命令,但是bash扩展的命令组合要求最后一个参数是],]不是命令要求后跟]]commandwordsplitting拆分单词,获取变量值,建议加双引号不拆分单词,获取变量值可以不加双引号展开路径名。为了转义路径名扩展的特殊字符,不进行路径名扩展。不支持算术运算。使用$((expr))算术展开获取运算结果支持算术运算,扩展模式匹配不需要使用$((expr))。不支持通配符模式匹配。==、=、!=运算符支持使用通配符判断字符串包含的模式匹配。=~运算符支持判断字符串包含关系。不支持扩展正则表达式=~支持运算符扩展正则表达式logicalANDuse-aoperatorANDuse&&operatorANDlogicalORuse-ooperatorORusetwopipeoperatorsoroperateparentheses需要对括号进行转义,或者引号不需要对括号进行转义,不需要加引号<、>写法需要转义<、>,或者引号不需要转义<、>,并且不带引号的<、>编码集比较字符串时用<、>,使用ASCII编码集当用<,>比较字符串时,使用当前语言环境的编码集
