我见过 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
编辑:这是一个更完整的版本,显示了 [
(又名 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
如果您想知道变量是否为非零长度,请执行以下任一操作:
在单括号中引用变量(第 2a 栏)
使用 -n 并在单括号中引用变量(第 4a 列)
使用带或不带引号和带或不带 -n 的双括号(第 1b - 4b 列)
请注意,在第 1a 列中,从标记为“二”的行开始,结果表明 [
正在评估变量的 内容,就好像它们是条件表达式的一部分一样(结果与隐含的断言相匹配由描述栏中的“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
相关帖子和文档
有很多与这个主题相关的帖子。这里有几个:
如何检查是否在 Bash 中设置了变量?
如何检查环境变量是否存在并获取其值?
如何在 Bash 中查找变量是否为空
shell 脚本表达式中的“加号”(“+:”)是什么意思?
在 Bash 中,双方括号 [[ ]] 是否优于单方括号 [ ]?
Bash中的单方括号和双方括号有什么区别?
mklement0 的一个很好的回答,他谈到 [[ vs [
Bash Hackers Wiki - [ vs [[
这里还有一些测试
如果字符串不为空,则为真:
[ -n "$var" ]
[[ -n $var ]]
test -n "$var"
[ "$var" ]
[[ $var ]]
(( ${#var} ))
let ${#var}
test "$var"
如果字符串为空,则为真:
[ -z "$var" ]
[[ -z $var ]]
test -z "$var"
! [ "$var" ]
! [[ $var ]]
! (( ${#var} ))
! let ${#var}
! test "$var"
正确答案如下:
if [[ -n $var ]] ; then
blah
fi
请注意 [[...]]
的使用,它为您正确处理引用变量。
-n
?
-n
和 -z
测试运算符,但随后在其上添加了 !
否定。此外,这在概念上与高级语言中 ==
和 !=
之间的区别相同,高级语言提供肯定和否定运算符只是为了扩展可能的语义范围。有时组装一个不需要依赖双重否定等的表达式要容易得多。
评估空环境变量的另一种可能更透明的方法是使用...
if [ "x$ENV_VARIABLE" != "x" ] ; then
echo 'ENV_VARIABLE contains something'
fi
bash
是比其前身更锋利的工具。
[ "$ENV_VARIABLE" != "" ]
将在具有符合 POSIX 标准的 test
实现的每个 shell 上工作——不仅仅是 bash,还有 ash/dash/ksh/etc。
-a
或 -o
来组合测试,而是使用 [ ... ] && [ ... ]
或 [ ... ] || [ ... ]
并且唯一可以应用于在测试中使用任意变量数据的极端情况是明确关闭。
使用 case/esac
测试:
case "$var" in
"") echo "zero length";;
esac
case
的用途。
case
效果最好。
case
不适用于此类用途。
不定期副业成功案例分享
["
与[-n"
(OP 的第一个问题)的图表显示它们是完全等价的,对吧?[["