在 Linux bash shell 中,使用 test 内置命令、[ 内置命令、和 [[ 内置命令进行判断时,所提供的参数个数会影响判断结果。
下面以 test 命令为例介绍具体的影响,这些说明也适用于 [ 命令、[[ 命令。
查看 man bash 里面对 test 命令不同参数个数的判断结果说明如下:
test and [ evaluate conditional expressions using a set of rules
based on the number of arguments.
0 arguments
The expression is false.
1 argument
The expression is true if and only if the argument is not null.
2 arguments
If the first argument is !, the expression is true if and only if
the second argument is null. If the first argument is one of the
unary conditional operators listed above under CONDITIONAL EXPRESSIONS,
the expression is true if the unary test is true. If the first argument
is not a valid unary conditional operator, the expression is false.
3 arguments
The following conditions are applied in the order listed. If the second
argument is one of the binary conditional operators listed above under
CONDITIONAL EXPRESSIONS, the result of the expression is the result of
the binary test using the first and third arguments as operands. If the
first argument is !, the value is thenegation of the two-argument test
using the second and third arguments.
针对不同的参数个数,具体举例说明如下。
0 arguments
$ test; echo $?
1
这里直接执行 test 命令,不提供任何参数。
参考上面 "0 arguments" 的说明,这种情况下的返回值总是 false。
用 echo $? 打印返回值为 1。
注意 test 命令把 1 作为 false。
1 argument
$ test -n; echo $?
0
$ test -z; echo $?
0
$ test -y; echo $?
0
$ set -x
$ test ""; echo $?;
+ test ''
+ echo 1
1
$ test $dummy; echo $?
+ test
+ echo 1
1
$ set +x
这里单独执行 test -n 和 test -z 这两个命令。
用 echo $? 打印这两个命令的返回值为 0,都是返回 true。
注意 test 命令把 0 作为 true。
参考上面 "1 argument" 的说明,只提供一个参数时,只要该参数不为空,就会返回 true。
此时的 -n 和 -z 被当作普通的字符串参数,没被当作 test 命令的操作符。
可以看到执行 test -y 也是返回 true。
但是 test 命令并不支持 -y 操作符。
在 help test 的说明中,test STRING 命令在 STRING 不为空时会返回 true,使用的就是只提供一个参数时的判断规则。
注意区分上面 test "" 和 test $dummy 的区别。
查看上面打印的调试信息,test "" 经过 bash 扩展,得到的结果是 test ''。
也就是确实有一个参数,这个参数是空字符串。
按照 "1 argument" 的说明,此时返回结果是 false。
由于没有定义 dummy 变量,test $dummy 经过 bash 扩展,得到的结果只有 test,没有提供参数。
按照 "0 arguments" 的说明,返回值为 false。
即,虽然 test "" 和 test $dummy 都返回 false,但是它们的参数个数不同,得出结果的原因也不同。
2 arguments
$ test -y go; echo $?
-bash: test: -y: unary operator expected
2
$ test -n go; echo $?
0
$ value=""; set -x
$ test ! -n $value; echo $?
+ test '!' -n
+ echo 1
1
$ test ! -n "$value"; echo $?
+ test '!' -n ''
+ echo 0
0
$ set +x
参考上面 "2 arguments" 的说明,提供两个参数时,如果第一个参数不是 unary conditional operator,返回结果是 false。
由于 test 命令不支持 -y 操作符,执行 test -y go 命令报错。
执行 test -n go 命令则会返回 -n 操作符对后面参数的判断结果。
注意区分上面 test ! -n $value 和 test ! -n "$value" 的区别。
上面将 value 变量设成空字符串,test ! -n $value 经过 bash 扩展,得到的结果是 test '!' -n,提供了两个参数。
按照 "2 arguments" 的说明,当第一个参数是 ! 时,只有第二个参数是空,才会返回 true。
这里的第二个参数不是空,所以返回 false。
而 test ! -n "$value" 扩展后的结果是 test '!' -n '',提供了三个参数。
按照 "3 arguments" 说明的规则来进行判断,会对后面两个参数的判断结果进行取反。
这里最终返回 true。
3 arguments
$ test -n go on
-bash: test: go: binary operator expected
在这个测试例子中,在 test -n 后面的字符串包含空格,又没有用双引号把字符串括起来,那么参数个数会变多。
这里提供了三个参数,-n 也是一个参数。
参考上面 "3 arguments" 的说明,提供三个参数时,预期第二个参数是 binary conditional operators。
由于这里没有提供,执行报错,提示 "go: binary operator expected"。
也就是所给的第二个参数 "go" 预期是一个 "binary operator",但它不是。
总结
总的来说,不加双引号来引用变量值,当参数值为空、或者包含空格时,会导致 test 命令的参数个数发生变化。
之后按照不同参数个数的判断规则进行处理,可能会导致不预期的结果。
结合上面几个例子可以看到,用双引号把变量值括起来,只会得到一个参数,保持参数个数不变,可以避免很多异常。