龙空技术网

Bash技巧:对比 test、[、[[ 判断字符串是否为空的用法

霜鱼片 356

前言:

而今各位老铁们对“判断表达式是否为空时使用的关键字是什么”大致比较关注,咱们都想要学习一些“判断表达式是否为空时使用的关键字是什么”的相关知识。那么小编也在网络上搜集了一些有关“判断表达式是否为空时使用的关键字是什么””的相关资讯,希望大家能喜欢,小伙伴们快快来学习一下吧!


在 Linux bash shell 中,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 $?

$ value="go on"

$ [[ -n $value ]]; echo $?

$ [[ -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 ]] 会执行报错。

标签: #判断表达式是否为空时使用的关键字是什么