如何判断一个string是不是在bash shell脚本中定义的?

如果我想检查空string,我会做的

[ -z $mystr ] 

但是如果我想检查variables是否被定义了呢? 或者是没有区分bash脚本?

我认为你以后的答案暗示了(如果没有说明的话) 温科的答案 ,尽pipe这不是简单的解释。 为了区分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 

您可能可以将第二行的两个testing合并为一个:

 if [ -z "$VAR" -a "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi 

但是,如果您阅读Autoconf的文档,则会发现他们不build议将术语与“ -a ”相结合,并build议使用单独的简单testing与&&结合使用。 我还没遇到一个有问题的系统。 这并不意味着他们以前不存在(但是他们现在可能非常罕见,即使他们在遥远的过去并不稀罕)。

您可以在Bash手册中find这些的详细信息,以及其他相关的shell参数扩展 , test[命令和条件expression式 。


最近我通过电子邮件询问了这个问题的答案:

你使用两个testing,我理解第二个,但不是第一个。 更确切地说,我不了解可变扩展的需要

 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 

公平的问题 – 答案是“不,你简单的select不会做同样的事情”。

假设我在testing之前写下这个:

 VAR= 

你的testing会说“VAR根本没有设置”,但我会说(暗示,因为它什么都没有响应)“VAR设置,但它的值可能是空的”。 试试这个脚本:

 ( 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 

在第二对testing中,variables被设置,但它被设置为空值。 这是${VAR=value}${VAR:=value}符号的区别。 对于${VAR-value}${VAR:-value}以及${VAR+value}${VAR:+value}等等,同样如此。


正如Gili在他的回答中指出的那样,如果使用set -o nounset选项运行bash ,那么上面的基本答案会失败,并显示unbound variable 。 它很容易补救:

 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 

或者你可以用set +uset -u等同于set -o nounset )来取消set -o nounset选项。

 ~> 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也适用于未定义的variables。 要区分一个未定义的和已定义的,你可以使用这里列出的东西,或者更清楚的解释。

最干净的方式就是在这些例子中使用扩展。 要获得所有选项,请检查手册的参数扩展部分。

备用字:

 ~$ 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。 参数replace:

  • $ {var + blahblah}:如果var被定义,则用'blahblah'代替expression式,否则null被replace
  • $ {var-blahblah}:如果var被定义,它本身被replace,否则'blahblah'被replace
  • $ {var?blahblah}:如果var被定义,则被replace,否则该函数以'blahblah'作为错误信息存在。

根据您的程序逻辑是否定义variables$ mystr,您可以执行以下操作:

 isdefined=0 ${mystr+ export isdefined=1} 

现在,如果isdefined = 0,那么variables是未定义的,如果isdefined = 1,则variables被定义

这种检查variables的方式比上面的答案要好,因为它更优雅,更易读,而且如果你的bash shell被configuration为使用未定义variables(set -u) ,那么脚本将提前终止。

其他有用的东西:

如果它是未定义的,则将默认值7分配给$ mystr,否则保持原样:

 mystr=${mystr- 7} 

如果variables未定义,则打印出错信息并退出函数:

 : ${mystr? not defined} 

在这里注意我使用了':',以免定义$ mystr的内容作为命令执行。

testing的总结。

 [ -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 

检查被定义variables的显式方法是:

 [ -v mystr ] 

另一种select: “列表数组索引”扩展 :

 $ unset foo $ foo= $ echo ${!foo[*]} 0 $ foo=bar $ echo ${!foo[*]} 0 $ foo=(bar baz) $ echo ${!foo[*]} 0 1 

这个扩展到空string的唯一时间是当foo未被设置,所以你可以用string条件来检查它:

 $ unset foo $ [[ ${!foo[*]} ]]; echo $? 1 $ foo= $ [[ ${!foo[*]} ]]; echo $? 0 $ foo=bar $ [[ ${!foo[*]} ]]; echo $? 0 $ foo=(bar baz) $ [[ ${!foo[*]} ]]; echo $? 0 

应该可以在任何bash版本中使用> = 3.0

不要更进一步地摆脱这个自行车,而是要补充

 shopt -s -o nounset 

是你可以添加到脚本的顶部的东西,如果在脚本的任何地方没有声明variables的话,这将会出错。 您将看到的消息是unbound variable ,但正如其他人提到的,它不会捕获空string或空值。 为了确保任何单独的值不为空,我们可以testing一个variables,因为它是用${mystr:?}扩展的,也就是美元符号扩展,这个parameter null or not set

Bash参考手册是有关bash信息的权威来源。

下面是一个testingvariables的例子,看它是否存在:

 if [ -z "$PS1" ]; then echo This shell is not interactive else echo This shell is interactive fi 

(从6.3.2节 )

请注意,打开[之前]和之前的空白不是可选的


Vim用户的提示

我有一个脚本,有几个声明如下:

 export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part" 

但我希望他们遵循任何现有的价值观。 所以我重新写他们看起来像这样:

 if [ -z "$VARIABLE_NAME" ]; then export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part" fi 

我能够使用快速正则expression式在vim中自动化:

 s/\vexport ([A-Z_]+)\=("[^"]+")\n/if [ -z "$\1" ]; then\r export \1=\2\rfi\r/gc 

这可以通过直观地select相关行来应用,然后键入: 。 命令栏预填充:'<,'> 。 粘贴上面的命令,然后回车。


testingVim的这个版本:

 VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Aug 22 2015 15:38:58) Compiled by root@apple.com 

Windows用户可能需要不同的行结束符。

这是我认为是一个更清晰的方式来检查是否定义了一个variables:

 var_defined() { local var_name=$1 set | grep "^${var_name}=" 1>/dev/null return $? } 

使用它如下:

 if var_defined foo; then echo "foo is defined" else echo "foo is not defined" fi 

调用集没有任何参数..它输出所有的variables定义..
列表中的最后一个将是你的脚本中定义的那些。
所以你可以通过pipe道输出来找出什么东西是被定义的,什么不是