在 bash 中,test
命令、[
命令、[[
命令都可以用于进行一些判断。
例如,这三个命令都可以用来判断字符串是否为空。
实际使用时,这几个命令的用法有一些异同和一些注意事项。
具体说明如下。
test 命令 和 [ 命令的关系
在 bash 中,[
关键字本身是一个命令,它不是 if
命令的一部分。
执行 help [
命令,有如下说明:
[: [ arg... ]
Evaluate conditional expression.
This is a synonym for the "test" builtin, but the last argument must be a literal]
, to match the opening[
.
即,[
命令是 test
命令的同义词,它对条件表达式的判断结果和 test
命令完全一样。
但是 [
命令要求该命令的最后一个参数必须是 ]
,看起来是闭合的方括号效果。
在实际使用中,test
命令 和 [
命令常常跟 if
命令、while
命令结合使用。
但这并不是必须的。test
命令 和 [
命令本身都是独立的命令,可以单独执行。
后面会统一用 test
命令来说明它的用法。这些说明都适用于 [
命令。
注意:]
自身不是 bash 的命令,它只是 [
命令要求的参数,且必须是最后一个参数。
注意:在使用 [
命令时,最大的误区是在这个命令之后没有加空格。
例如 [string1 != string2]
这种写法是错误的。
要时刻注意 [
本身是一个命令,这个命令名就是 [
。
在这个命令之后会跟着一些参数,要用空格把命令名和参数隔开。 [string1
这个写法实际上会执行名为 [string1
的命令,不是执行 [
命令。
类似的,]
本身是一个参数,它也要用空格来隔开其他参数。 string2]
这个写法实际上是一个名为 "string2]" 的参数。
而不是 string2
和 ]
两个参数。
用 test 命令判断字符串是否为空
执行 help test
命令,有如下说明:
test: test [expr]
Evaluate conditional expression.
Exits with a status of 0 (true) or 1 (false) depending on
the evaluation of EXPR.
The behavior of test depends on the number of arguments.
Read the bash manual page for the complete specification.
String operators:
-z STRING True if string is empty.
-n STRING
STRING True if string is not empty.
即,test
命令使用 -z STRING
操作符来判断 STRING 字符串的长度是否为 0。
如果为 0,就是空字符串,会返回 true。
具体写法是 test -z STRING
,使用 [
命令则写为 [ -z STRING ]
。
-n STRING
操作符判断 STRING 字符串的长度是否为 0。
如果不为 0,就不是空字符串,会返回 true。
具体写法是 test -n STRING
,使用 [
命令则写为 [ -n STRING ]
。
可以省略 -n
操作符,直接写为 test STRING
、或者 [ STRING ]
。
注意:在实际使用时,要注意下面几点:
- 当判断变量值对应的字符串是否为空时,一定要用双引号把变量值括起来。否则变量值为空、或者带有空格时,会返回异常的结果。
例如,要写为test -n "$string"
,不建议写为test -n $string
。 - bash 是以 0 作为 true,以 1 作为 false。上面
test
命令的说明也是如此。
而大部分编程语言是以 1 作为 true,0 作为 false。要注意区分,避免搞错判断条件的执行关系。 - 上面
help test
的说明提到,test 命令的参数个数会影响它的行为。具体要参考 man bash 的说明。
不同的参数个数会导致test
命令返回很多不预期的结果。
下面用一个 empty_string.sh
脚本来举例说明 test
命令和 [
命令判断字符串是否为空的方法,其内容如下:
#!/bin/bash
function empty_string()
{
if test -n $1; then
echo '(1) -n $1 :' "No quote: not empty."
fi
if [ -z $1 ]; then
echo '(2) -z $1 :' "No quote: empty."
fi
if test -n "$1"; then
echo '(3) -n "$1":' "Quote : not empty."
fi
if [ -z "$1" ]; then
echo '(4) -z "$1":' "Quote : empty."
fi
}
empty_string "$1"
这个脚本使用 test
命令的 -n
、-z
操作符来判断传入脚本的第一个参数是否为空字符串,并对比加双引号和不加双引号把变量值括起来的测试结果。
具体执行结果如下:
$ ./empty_string.sh go
(1) -n $1 : No quote: not empty.
(3) -n "$1": Quote : not empty.
$ ./empty_string.sh "go on"
./empty_string.sh: line 5: test: go: binary operator expected
./empty_string.sh: line 9: [: go: binary operator expected
(3) -n "$1": Quote : not empty.
$ ./empty_string.sh
(1) -n $1 : No quote: not empty.
(2) -z $1 : No quote: empty.
(4) -z "$1": Quote : empty.
可以看到,执行 ./empty_string.sh go
命令,传入的第一个参数值没有包含空格,$1
变量值加不加双引号的判断结果都正确。
执行 ./empty_string.sh "go on"
命令,传入的第一个参数值包含空格。 $1
变量值不加双引号的语句执行报错,提示 "binary operator expected"。 test
命令在 -n
、-z
操作符后面预期只有一个参数。
而这里的 test -n $1
扩展为 test -n test string
。
在 -n
后面提供了两个参数,加上 -n
总共是三个参数,导致执行报错。
使用双引号把 $1
变量值括起来,整个变量值就会被当成一个参数,执行 test -n "$1"
命令不会报错。
执行 ./empty_string.sh
命令,没有提供第一个参数,测试结果比较奇怪。 -n $1
认为 $1
不为空。
而 -z $1
又认为 $1
为空。
只有 -z "$1"
正确地判断出第一个参数值为空。
原因在于,没有提供第一个参数时,这里的 $1
的值是空,相当于什么都没有。 test -n $1
语句经过 bash 处理后,得到的是 test -n
。 [ -z $1 ]
语句经过 bash 处理后,得到的是 [ -z ]
,相当于 test -z
。 test -n
和 test -z
的返回结果都是 true。
所以才打印出来 $1
即为空,又不为空,判断结果不符合预期。
可以再次看到,-z "$1"
用双引号把变量值括起来,得到了预期的判断结果。
添加双引号可以避免很多异常的现象。
使用 bash -x ./empty_string.sh
打印执行脚本时的调试信息,可以看到 [ -z $1 ]
和 [ -z "$1" ]
扩展结果的区别:
$ bash -x ./empty_string.sh
+ empty_string ''
+ test -n
+ echo '(1) -n $1 :' 'No quote: not empty.'
(1) -n $1 : No quote: not empty.
+ '[' -z ']'
+ echo '(2) -z $1 :' 'No quote: empty.'
(2) -z $1 : No quote: empty.
+ test -n ''
+ '[' -z '' ']'
+ echo '(4) -z "$1":' 'Quote : empty.'
(4) -z "$1": Quote : empty.
结合上面的代码,可以看到 [ -z $1 ]
扩展得到的调试信息是 '[' -z ']'
,在 -z
后面没有任何参数。
而 [ -z "$1" ]
扩展得到的结果是 '[' -z '' ']'
。
在 -z
后有一个参数 ''
,这个参数的值是空字符串。
用 [[ 命令判断字符串是否为空
查看 help [[
对 [[
命令说明如下:
[[ ... ]]: [[ expression ]]
Execute conditional command.
Returns a status of 0 or 1 depending on the evaluation of the conditional
expression EXPRESSION. Expressions are composed of the same primaries used
by the 'test' builtin, and may be combined using the following operators:
( EXPRESSION ) Returns the value of EXPRESSION
! EXPRESSION True if EXPRESSION is false; else false
EXPR1 && EXPR2 True if both EXPR1 and EXPR2 are true; else false
EXPR1 || EXPR2 True if either EXPR1 or EXPR2 is true; else false
即,[[
命令可以使用 test
命令所支持的条件表达式来进行判断。
它们之间的一些区别具体说明如下。
上面提到,[
命令要求最后一个参数必须是 ]
,]
本身不是一个命令。
类似的,[[
命令也要求跟 ]]
同时出现。但是 ]]
本身也是一个命令,而不是一个参数。
所以 [[ expression ]]
被称为复合命令 (compound command)。
如下面例子所示:
$ ]
]: command not found
$ ]]
-bash: syntax error near unexpected token `]]'
可以看到,试图执行 ]
命令,提示命令没有找到,说明没有这个命令。
而执行 ]]
命令,没有提示找不到命令,只是提示语法错误,预期在该命令之前要有 [[
命令。
由于 [[
和 ]]
都是命令,需要用空格把它们和其他参数隔开。
查看 man bash 里面对 [[
有如下说明:
Word splitting and pathname expansion are not performed on the words between the [[ and ]]; tilde expansion, parameter and variable expansion, arithmetic expansion, command substitution, process substitution, and quote removal are performed.
即,在 [[
和 ]]
里面引用变量值时,不会对变量值进行单词拆分 (Word splitting)。
即使变量值带有空格,不用双引号括起来也不会被拆分成多个参数。
而 test
命令 和 [
命令会进行单词拆分,可能会导致参数个数发生变化。
可以参考前面几个例子的说明。
使用 [[
判断字符串是否为空的一些例子如下所示:
$ value=
$ [[ -n $value ]]; echo $?
1
$ [[ -z $value ]]; echo $?
0
$ value="go on"
$ [[ -n $value ]]; echo $?
0
$ [[ -n go on ]]; echo $?
-bash: syntax error in conditional expression
-bash: syntax error near 'on'
可以看到,将 value 变量值设成空,[[ -n $value ]]
返回为 1,确认该变量值不为空是 false。
[[ -z $value ]]
返回为 0,确认该变量值为空是 true。
即使 $value
不加双引号,也能正确判断。
如果是用 [
命令就会判断异常。
当 value 变量值包含空格时,[[ -n $value ]]
可以正确判断,但是如果直接写为 [[ -n go on ]]
会执行报错。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。