我已经看到bash脚本以两种不同的方式测试非零长度字符串。大多数脚本使用-n选项:
#!/bin/bash
# With the -n option
if [ -n "$var" ]; then
# Do something when var is non-zero length
fi
但是-n选项并不是真正需要的:
# Without the -n option
if [ "$var" ]; then
# Do something when var is non-zero length
fi
哪种方式更好?
同样,这是测试零长度的更好方法:
if [ -z "$var" ]; then
# Do something when var is zero-length
fi
要么
if [ ! "$var" ]; then
# Do something when var is zero-length
fi
编辑:这是一个更完整的版本,显示[
(aka test
)和[[
之间的更多差异。
下表显示是否引用变量,是否使用单括号或双括号以及变量是否仅包含空格,这些因素会影响使用带或不带-n/-z
的测试是否适合检查变量。
| 1a 2a 3a 4a 5a 6a | 1b 2b 3b 4b 5b 6b
| [ [" [-n [-n" [-z [-z" | [[ [[" [[-n [[-n" [[-z [[-z"
-----+------------------------------------+------------------------------------
unset| false false true false true true | false false false false true true
null | false false true false true true | false false false false true true
space| false true true true true false| true true true true false false
zero | true true true true false false| true true true true false false
digit| true true true true false false| true true true true false false
char | true true true true false false| true true true true false false
hyphn| true true true true false false| true true true true false false
two | -err- true -err- true -err- false| true true true true false false
part | -err- true -err- true -err- false| true true true true false false
Tstr | true true -err- true -err- false| true true true true false false
Fsym | false true -err- true -err- false| true true true true false false
T= | true true -err- true -err- false| true true true true false false
F= | false true -err- true -err- false| true true true true false false
T!= | true true -err- true -err- false| true true true true false false
F!= | false true -err- true -err- false| true true true true false false
Teq | true true -err- true -err- false| true true true true false false
Feq | false true -err- true -err- false| true true true true false false
Tne | true true -err- true -err- false| true true true true false false
Fne | false true -err- true -err- false| true true true true false false
如果您想知道变量的长度是否为非零,请执行以下任一操作:
-n
并在单括号中引用变量(第4a列)-n
(第1b - 4b列)从第1a列开始,注意标记为“two”的行,结果表明[
正在评估变量的内容,就好像它们是条件表达式的一部分一样(结果与“T”或“F”隐含的断言相匹配)在说明栏中)。当使用[[
时(第1b列),变量内容被视为字符串而不进行评估。
列3a和5a中的错误是由变量值包括空格而变量未加引号的事实引起的。同样,如列3b和5b所示,[[
将变量的内容评估为字符串。
相应地,对于零长度字符串的测试,列6a,5b和6b显示了正确的方法。还要注意,如果否定显示比使用相反操作更清晰的意图,则可以否定这些测试中的任何一个。例如:if ! [[ -n $var ]]
。
如果你正在使用[
,那么确保你没有得到意想不到的结果的关键是引用变量。使用[[
,没关系。
被抑制的错误消息是“一元运算符预期”或“二元运算符预期”。
这是生成上表的脚本。
#!/bin/bash
# by Dennis Williamson
# 2010-10-06, revised 2010-11-10
# for http://stackoverflow.com/q/3869072
# designed to fit an 80 character terminal
dw=5 # description column width
w=6 # table column width
t () { printf '%-*s' "$w" " true"; }
f () { [[ $? == 1 ]] && printf '%-*s' "$w" " false" || printf '%-*s' "$w" " -err-"; }
o=/dev/null
echo ' | 1a 2a 3a 4a 5a 6a | 1b 2b 3b 4b 5b 6b'
echo ' | [ [" [-n [-n" [-z [-z" | [[ [[" [[-n [[-n" [[-z [[-z"'
echo '-----+------------------------------------+------------------------------------'
while read -r d t
do
printf '%-*s|' "$dw" "$d"
case $d in
unset) unset t ;;
space) t=' ' ;;
esac
[ $t ] 2>$o && t || f
[ "$t" ] && t || f
[ -n $t ] 2>$o && t || f
[ -n "$t" ] && t || f
[ -z $t ] 2>$o && t || f
[ -z "$t" ] && t || f
echo -n "|"
[[ $t ]] && t || f
[[ "$t" ]] && t || f
[[ -n $t ]] && t || f
[[ -n "$t" ]] && t || f
[[ -z $t ]] && t || f
[[ -z "$t" ]] && t || f
echo
done <<'EOF'
unset
null
space
zero 0
digit 1
char c
hyphn -z
two a b
part a -a
Tstr -n a
Fsym -h .
T= 1 = 1
F= 1 = 2
T!= 1 != 2
F!= 1 != 1
Teq 1 -eq 1
Feq 1 -eq 2
Tne 1 -ne 2
Fne 1 -ne 1
EOF
就Bash而言,最好使用more powerful [[
。
if [[ $var ]]; then # var is set and it is not empty
if [[ ! $var ]]; then # var is not set or it is set to an empty string
以上两种结构看起来干净可读。在大多数情况下,它们应该足够了。
请注意,我们不需要在[[
中引用变量扩展,因为没有word splitting和globbing的危险。
为了防止shellcheck对[[ $var ]]
和[[ ! $var ]]
的软性抱怨,我们可以使用-n
选项。
在极少数情况下,我们必须区分“被设置为空字符串”与“未被设置”,我们可以使用这些:
if [[ ${var+x} ]]; then # var is set but it could be empty
if [[ ! ${var+x} ]]; then # var is not set
if [[ ${var+x} && ! $var ]]; then # var is set and is empty
我们也可以使用-v
测试:
if [[ -v var ]]; then # var is set but it could be empty
if [[ ! -v var ]]; then # var is not set
if [[ -v var && ! $var ]]; then # var is set and is empty
if [[ -v var && -z $var ]]; then # var is set and is empty
有很多与此主题相关的帖子。以下是一些:
[[
vs [
[
vs [[
这是一些更多的测试
如果string不为空,则为true:
[ -n "$var" ]
[[ -n $var ]]
test -n "$var"
[ "$var" ]
[[ $var ]]
(( ${#var} ))
let ${#var}
test "$var"
如果string为空,则为true:
[ -z "$var" ]
[[ -z $var ]]
test -z "$var"
! [ "$var" ]
! [[ $var ]]
! (( ${#var} ))
! let ${#var}
! test "$var"
用case/esac
来测试
case "$var" in
"") echo "zero length";;
esac
评估空env变量的另一种可能更透明的方法是使用......
if [ "x$ENV_VARIABLE" != "x" ] ; then
echo 'ENV_VARIABLE contains something'
fi
正确答案如下:
if [[ -n $var ]] ; then
blah
fi
请注意[[...]]
的使用,它正确处理为您引用变量。