在 Bash 中,如何测试变量是否以“-u”模式定义

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11362250/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 22:22:59  来源:igfitidea点击:

In Bash, how do I test if a variable is defined in "-u" mode

bash

提问by Ramon

I just discovered set -uin bash and it helped me find several previously unseen bugs. But I also have a scenario where I need to test if a variable is defined before computing some default value. The best I have come up with for this is:

我刚刚set -u在 bash 中发现,它帮助我找到了几个以前看不见的错误。但我也有一个场景,我需要在计算一些默认值之前测试是否定义了一个变量。我为此想到的最好的方法是:

if [ "${variable-undefined}" == undefined ]; then
    variable="$(...)"
fi

which works (as long as the variable doesn't have the string value undefined). I was wondering if there was a better way?

哪个有效(只要变量没有字符串值undefined)。我想知道是否有更好的方法?

采纳答案by Todd A. Jacobs

What Doesn't Work: Test for Zero-Length Strings

什么不起作用:测试零长度字符串

You can test for undefined strings in a few ways. Using the standard test conditional looks like this:

您可以通过几种方式测试未定义的字符串。使用标准测试条件如下所示:

# Test for zero-length string.
[ -z "$variable" ] || variable='foo'

This will not work with set -u, however.

但是,这不适用于set -u

What Works: Conditional Assignment

什么有效:条件分配

Alternatively, you can use conditional assignment, which is a more Bash-like way to do this. For example:

或者,您可以使用条件赋值,这是一种更类似于 Bash 的方式来执行此操作。例如:

# Assign value if variable is unset or null.
: "${variable:=foo}"

Because of the way Bash handles expansion of this expression, you can safely use this with set -uwithout getting a "bash: variable: unbound variable" error.

由于 Bash 处理此表达式扩展的方式,您可以安全地使用它set -u而不会出现“bash:变量:未绑定变量”错误。

回答by Ramon

This is what I've found works best for me, taking inspiration from the other answers:

这是我发现最适合我的方法,从其他答案中汲取灵感:

if [ -z "${varname-}" ]; then
  ...
  varname=$(...)
fi

回答by Felix Leipold

In bash 4.2 and newer there is an explicit way to check whether a variable is set, which is to use -v. The example from the question could then be implemented like this:

在 bash 4.2 和更新版本中,有一种明确的方法来检查是否设置了变量,即使用 -v。然后可以像这样实现问题中的示例:

if [[ ! -v variable ]]; then
   variable="$(...)"
fi

See http://www.gnu.org/software/bash/manual/bashref.html#Bash-Conditional-Expressions

请参阅http://www.gnu.org/software/bash/manual/bashref.html#Bash-Conditional-Expressions

If you only want to set the variable, if it is not already set you are probably better of doing something along these lines:

如果您只想设置变量,如果它尚未设置,您可能最好按照以下方式做一些事情:

variable="${variable-$(...)}"

variable="${variable-$(...)}"

Note that this does not deal with a defined but empty variable.

请注意,这不处理已定义但为空的变量。

回答by kevinarpe

The answers above are not dynamic, e.g., how to test is variable with name "dummy" is defined? Try this:

上面的答案不是动态的,例如,如何测试定义了名称为“dummy”的变量?尝试这个:

is_var_defined()
{
    if [ $# -ne 1 ]
    then
        echo "Expected exactly one argument: variable name as string, e.g., 'my_var'"
        exit 1
    fi
    # Tricky.  Since Bash option 'set -u' may be enabled, we cannot directly test if a variable
    # is defined with this construct: [ ! -z "$var" ].  Instead, we must use default value
    # substitution with this construct: [ ! -z "${var:-}" ].  Normally, a default value follows the
    # operator ':-', but here we leave it blank for empty (null) string.  Finally, we need to
    # substitute the text from  as 'var'.  This is not allowed directly in Bash with this
    # construct: [ ! -z "${:-}" ].  We need to use indirection with eval operator.
    # Example: ="var"
    # Expansion for eval operator: "[ ! -z ${:-} ]" -> "[ ! -z ${var:-} ]"
    # Code  execute: [ ! -z ${var:-} ]
    eval "[ ! -z ${:-} ]"
    return $?  # Pedantic.
}

Related: How to check if a variable is set in Bash?

相关:如何检查 Bash 中是否设置了变量?

回答by efa

Unfortunatly [[ -v variable ]]is not supported in older versions of bash (at least not in version 4.1.5 I have on Debian Squeeze)

不幸的[[ -v variable ]]是,旧版本的 bash 不支持(至少在 Debian Squeeze 上的 4.1.5 版本中不支持)

You could instead use a sub shell as in this :

您可以改为使用子 shell,如下所示:

if (true $variable)&>/dev/null; then
    variable="$(...)"
fi

回答by Luc M

In the beginning of your script, you could define your variables with an empty value

在脚本的开头,您可以使用空值定义变量

variable_undefined=""

Then

然后

if [ "${variable_undefined}" == "" ]; then
    variable="$(...)"
fi

回答by George

if [ "${var+SET}" = "SET" ] ; then
    echo "$var = ${var}"
fi

I don't know how far back ${var+value} is supported, but it works at least as far back as 4.1.2. Older versions didn't have ${var+value}, they only had ${var:+value}. The difference is that ${var:+value} will only evaluate to "value" if $var is set to a nonemptystring, while ${var+value} will also evaluate to "value" if $var is set to the empty string.

我不知道支持多远的 ${var+value},但它至少可以追溯到 4.1.2。旧版本没有 ${var+value},他们只有 ${var:+value}。不同之处在于,如果 $var 设置为非空字符串,则${var:+value} 只会计算为“value”,而如果 $var 设置为字符串,则 ${var+value} 也会计算为“value”细绳。

Without [[ -v var ]] or ${var+value} I think you'd have to use another method. Probably a subshell test as was described in a previous answer:

如果没有 [[ -v var ]] 或 ${var+value} 我认为你必须使用另一种方法。可能是先前答案中描述的子外壳测试:

if ( set -u; echo "$var" ) &> /dev/null; then
    echo "$var = ${var}
fi

If your shell process has "set -u" active already it'll be active in the subshell as well without the need for "set -u" again, but including it in the subshell command allows the solution to also work if the parent process hasn't got "set -u" enabled.

如果您的 shell 进程已经激活了“set -u”,它也会在子 shell 中处于活动状态,而无需再次使用“set -u”,但是将它包含在 subshel​​l 命令中允许解决方案在父进程中也能工作没有启用“set -u”。

(You could also use another process like "printenv" or "env" to test for the presence of the variable, but then it'd only work if the variable is exported.)

(您也可以使用“printenv”或“env”等其他过程来测试变量是否存在,但只有在导出变量时它才有效。)