我如何知道是否在Bash中设置了变量?

例如,如何检查用户是否向函数提供了第一个参数?

function a {
    # if $1 is set ?
}

当前回答

如果你想检查$@中的任何内容,我找到了一个更好的代码。

if [[ $1 = "" ]]
then
  echo '$1 is blank'
else
  echo '$1 is filled up'
fi

为什么会这样?$@中的所有内容都存在于Bash中,但默认情况下为空,因此test-z和test-n无法帮助您。

更新:您还可以计算参数中的字符数。

if [ ${#1} = 0 ]
then
  echo '$1 is blank'
else
  echo '$1 is filled up'
fi

其他回答

要检查非空/非零字符串变量,即如果已设置,请使用

if [ -n "$1" ]

它与-z相反。我发现自己使用-n多于-z。

您可以像这样使用它:

if [ -n "$1" ]; then
  echo "You supplied the first parameter!"
else
  echo "First parameter not supplied."
fi

我总是使用这个,因为任何第一次看到代码的人都很容易理解:

if [ "$variable" = "" ]
    then
    echo "Variable X is empty"
fi

如果要检查是否为空;

if [ ! "$variable" = "" ]
    then
    echo "Variable X is not empty"
fi

就是这样。

要测试是否设置了变量var:[${var+x}]。

若要测试变量是否按名称设置:[${!name+x}]。

要测试是否设置了位置参数:[${N+x}],其中N实际上是一个整数。

这个答案与莱昂内尔的答案几乎相似,但通过省略-z来探索一种更为简约的方法。

要测试是否设置了命名变量,请执行以下操作:

function is_set {
    local v=$1
    echo -n "${v}"
    if [ ${!v+x} ]; then
        echo " = '${!v}'"
    else
        echo " is unset"
    fi
}

要测试是否设置了位置参数:

function a {
    if [ ${1+x} ]; then
        local arg=$1
        echo "a '${arg}'"
    else
        echo "a: arg is unset"
    fi
}

测试表明,不需要特别注意空格和有效的测试表达式。

set -eu

V1=a
V2=
V4=-gt
V5="1 -gt 2"
V6="! -z 1"
V7='$(exit 1)'

is_set V1
is_set V2
is_set V3
is_set V4
is_set V5
is_set V6
is_set V7

a 1
a
a "1 -gt 2"
a 1 -gt 2
$ ./test.sh

V1 = 'a'
V2 = ''
V3 is unset
V4 = '-gt'
V5 = '1 -gt 2'
V6 = '! -z 1'
V7 = '$(exit 1)'
a '1'
a: arg is unset
a '1 -gt 2'
a '1'

最后,请注意set-eu,它保护我们避免常见错误,例如变量名中的拼写错误。我建议使用它,但这意味着未设置的变量和带有空字符串的变量集之间的区别得到了正确处理。

(通常)正确的方式

if [ -z ${var+x} ]; then echo "var is unset"; else echo "var is set to '$var'"; fi

其中${var+x}是一个参数扩展,如果var未设置,则其求值结果为空,否则替换字符串x。

报价摘要

可以省略引号(所以我们可以说${var+x}而不是“${var+x}”),因为这种语法和用法保证它只扩展到不需要引号的对象(因为它要么扩展到x(不包含换行符,因此不需要引号),要么不扩展到任何对象(这导致[-z],它方便地计算出与[-z“”]相同的值(true))。

然而,虽然可以安全地省略引号,而且这并不是所有人都能立即看到的(这对第一位也是主要Bash编码者的引号解释作者来说都不明显),但有时最好使用引号[-z“${var+x}”]来编写解决方案,代价很小,可能会导致O(1)速度损失。第一作者还将此添加为使用此解决方案的代码旁边的注释,给出了此答案的URL,现在还包括了为什么可以安全地省略引号的解释。

(经常)错误的方式

if [ -z "$var" ]; then echo "var is blank"; else echo "var is set to '$var'"; fi

这通常是错误的,因为它无法区分未设置的变量和设置为空字符串的变量。也就是说,如果var='',则上述解决方案将输出“var为空”。

在用户必须指定扩展名或其他财产列表的情况下,必须区分unset和“设置为空字符串”,如果不指定,则默认为非空值,而指定空字符串应使脚本使用空扩展名或附加财产列表。

然而,这种区别在每种情况下可能都不是必不可少的。在这种情况下,[-z“$var”]就可以了。

总结

使用test-n“${var-}”检查变量是否为空(因此也必须定义/设置)。用法:如果测试-n“${var-}”;然后echo“var设置为<$var>”其他的echo“var未设置或为空”传真使用test-n“${var+x}”检查变量是否已定义/设置(即使它是空的)。用法:如果测试-n“${var+x}”;然后echo“var设置为<$var>”其他的echo“var未设置”传真

注意,第一个用例在shell脚本中更常见,这是您通常想要使用的。

笔记

此解决方案应适用于所有POSIX shell(sh、bash、zsh、ksh、dash)这个问题的其他一些答案是正确的,但对于没有shell脚本经验的人来说可能会感到困惑,所以我想提供一个TLDR答案,这对这些人来说是最不困惑的。

解释

要了解此解决方案的工作原理,您需要了解POSIX测试命令和POSIX外壳参数扩展(spec),因此让我们介绍了解答案所需的绝对基础知识。

测试命令计算表达式并返回true或false(通过其退出状态)。如果操作数是非空字符串,则运算符-n返回true。例如,test-n“a”返回true,而test-n“”返回false。现在,要检查变量是否为空(这意味着必须定义它),可以使用test-n“$var”。然而,一些shell脚本有一个选项集(set-u),它会导致对未定义变量的任何引用都会发出错误,因此如果未定义变量var,表达式$var将导致错误。要正确处理这种情况,必须使用变量扩展,如果未定义变量,它将告诉shell用替换字符串替换变量,从而避免上述错误。

变量扩展${var-}表示:如果变量var未定义(也称为“unset”),请用空字符串替换它。因此,如果$var不为空,test-n“${var-}”将返回true,这几乎总是您想要在shell脚本中检查的。如果$var未定义或不为空,则反向检查将是test-z“${var-}”。

现在进入第二个用例:检查变量var是否已定义,无论是否为空。这是一个不太常见的用例,稍微复杂一点,我建议您阅读莱昂内尔的伟大答案,以更好地理解它。