如何判断 bash shell 脚本中是否未定义字符串?
题
如果我想检查空字符串我会这样做
[ -z $mystr ]
但如果我想检查变量是否已定义怎么办?或者 bash 脚本没有区别吗?
解决方案
我认为 Vinko 的答案,虽然没有简单说明。要区分VAR是否已设置但为空或未设置,您可以使用:
if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
if [ -z "$VAR" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi
你可能可以将第二行的两个测试合并为一个:
if [ -z "$VAR" -a "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi
但是,如果您阅读Autoconf的文档,您会发现他们不建议将术语与'-a
'结合使用,并建议使用单独的简单测试与&&
结合使用。我没遇到过有问题的系统;这并不意味着它们不曾存在(但它们现在可能非常罕见,即使它们在遥远的过去并不罕见)。
你可以找到这些的详细信息,以及其他相关的 shell参数扩展, test
或< => 命令和条件表达式在Bash手册中。
我最近通过电子邮件询问了这个问题的答案:
你使用两个测试,我理解第二个,但不是第一个。更确切地说,我不了解变量扩展的必要性
if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
这不会达到同样的效果吗?
if [ -z "${VAR}" ]; then echo VAR is not set at all; fi
公平的问题 - 答案是'不,你更简单的选择不会做同样的事情'。
假设我在测试之前写了这个:
VAR=
你的测试会说<!>“; VAR根本没有设置<!>”,但我会说(暗示因为它没有回应)<!>“; VAR已设置但其值可能为空<!> QUOT ;.试试这个脚本:
(
unset VAR
if [ -z "${VAR+xxx}" ]; then echo JL:1 VAR is not set at all; fi
if [ -z "${VAR}" ]; then echo MP:1 VAR is not set at all; fi
VAR=
if [ -z "${VAR+xxx}" ]; then echo JL:2 VAR is not set at all; fi
if [ -z "${VAR}" ]; then echo MP:2 VAR is not set at all; fi
)
输出结果为:
JL:1 VAR is not set at all
MP:1 VAR is not set at all
MP:2 VAR is not set at all
在第二对测试中,变量已设置,但设置为空值。这是[
和${VAR=value}
符号的区别。同上${VAR:=value}
和${VAR-value}
,${VAR:-value}
和${VAR+value}
,依此类推。
Gili 指出回答,如果您使用${VAR:+value}
选项运行bash
,则上面的基本答案将失败并显示set -o nounset
。这很容易解决:
if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
if [ -z "${VAR-}" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi
或者你可以用unbound variable
取消set +u
选项(set -u
等同于<=>)。
其他提示
~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO=""
~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO="a"
~> if [ -z $FOO ]; then echo "EMPTY"; fi
~>
-z也适用于未定义的变量。要区分未定义和已定义的内容,请使用此处列出的内容,或者使用更清晰的解释,此处。
最干净的方法是使用这些示例中的扩展。要获得所有选项,请查看手册的参数扩展部分。
替代词:
~$ unset FOO
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
~$ FOO=""
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
DEFINED
默认值:
~$ FOO=""
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
~$ unset FOO
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
UNDEFINED
当然,您可以使用其中一种方式,将所需值设为“默认值”并直接使用扩展(如果适用)。
高级 bash 脚本编写指南,10.2。参数替换:
- ${var+blahblah}:如果定义了var,则“ blahblah”被替换为表达式,否则null被取代
- ${var-blahblah}:如果定义了var,则可以替换,否则“ blahblah”被替换
- ${var?blahblah}:如果定义了var,则将其替换,否则用“ blahblah”作为错误消息而存在该函数。
要使程序逻辑基于变量 $mystr 是否已定义,您可以执行以下操作:
isdefined=0
${mystr+ export isdefined=1}
现在,如果 isdefine=0 则该变量未定义,如果 isdefine=1 则该变量已定义
这种检查变量的方法比上面的答案更好,因为它更优雅、更具可读性,并且如果您的 bash shell 配置为在使用未定义的变量时出错 (set -u)
, ,脚本将提前终止。
其他有用的东西:
如果 $mystr 未定义,则将默认值 7 分配给它,否则保持不变:
mystr=${mystr- 7}
如果变量未定义,则打印错误消息并退出函数:
: ${mystr? not defined}
请注意,这里我使用了“:”,以免在定义 $mystr 时将其内容作为命令执行。
测试摘要。
[ -n "$var" ] && echo "var is set and not empty"
[ -z "$var" ] && echo "var is unset or empty"
[ "${var+x}" = "x" ] && echo "var is set" # may or may not be empty
[ -n "${var+x}" ] && echo "var is set" # may or may not be empty
[ -z "${var+x}" ] && echo "var is unset"
[ -z "${var-x}" ] && echo "var is set and empty"
https://stackoverflow.com/a/9824943/14731 包含更好的答案(更易读的答案)并使用set -o nounset
启用)。它的工作方式大致如下:
if [ -n "${VAR-}" ]; then
echo "VAR is set and is not empty"
elif [ "${VAR+DEFINED_BUT_EMPTY}" = "DEFINED_BUT_EMPTY" ]; then
echo "VAR is set, but empty"
else
echo "VAR is not set"
fi
检查正在定义的变量的显式方法是:
[ -v mystr ]
另一种选择: <!>“;列表数组索引<!> quot;膨胀:
$ unset foo
$ foo=
$ echo ${!foo[*]}
0
$ foo=bar
$ echo ${!foo[*]}
0
$ foo=(bar baz)
$ echo ${!foo[*]}
0 1
唯一一次扩展为空字符串的时间是foo
未设置,因此您可以使用字符串条件检查它:
$ unset foo
$ [[ ${!foo[*]} ]]; echo $?
1
$ foo=
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=bar
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=(bar baz)
$ [[ ${!foo[*]} ]]; echo $?
0
应该可以在任何bash版本中使用<!> gt; = 3.0
不要进一步脱掉这辆自行车,但是想补充一下
shopt -s -o nounset
是您可以添加到脚本顶部的内容,如果变量未在脚本中的任何位置声明,则会出错。您看到的消息是unbound variable
,但正如其他人提到的那样,它不会捕获空字符串或空值。为了确保任何单个值不为空,我们可以测试一个变量,因为它是用${mystr:?}
扩展的,也称为美元符号扩展,这会因parameter null or not set
而出错。
调用set没有任何参数..它输出所有定义的变量..
列表中的最后一个将是您的脚本中定义的..
所以你可以把它的输出管道输出到可以找出什么东西定义的东西,而不是