使用函数测试未设置的 Bash 变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/874389/
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 18:11:18  来源:igfitidea点击:

Test for a Bash variable being unset, using a function

bashvariablesundefined

提问by DaveP

A simple Bash variable test goes:

一个简单的 Bash 变量测试如下:

${varName:?    "${varName} is not defined"}

I'd like to re-use this, by putting it in a function. How please?

我想通过将它放在一个函数中来重新使用它。请问怎么样?

Following fails

跟随失败

#
# Test a variable exists
tvar(){
 val=${1:?    "    must be defined, preferably in $basedir"}
 if [ -z ${val}  ]
     then 
     echo Zero length value 
 else
     echo  exists, value 
 fi
}

I.e. I need to exit if the test fails.

即如果测试失败我需要退出。

回答by Paused until further notice.

Thanks to lhunath'sanswer, I was led to a part of the Bash manpage that I've overlooked hundreds of times:

感谢lhunath 的回答,我被引导到了 Bashman页面的一部分,我已经忽略了数百次:

    When  not performing substring  expansion, bash tests for a parameter that
    is unset  or null; omitting the colon results in a test only for a parame‐
    ter that is unset.

This prompted me to create the following truth table:

这促使我创建以下真值表:

                | unset |   set    | set and  | meaning
                |       | but null | not null |
    ============+=======+==========+==========+=============================
     ${var-_}   |   T   |     F    |    T     | not null or not set
    ------------+-------+----------+----------+-----------------------------
     ${var:-_}  |   T   |     T    |    T     | always true, use for subst.
    ------------+-------+----------+----------+-----------------------------
     $var       |   F   |     F    |    T     | var is set and not null
    ------------+-------+----------+----------+-----------------------------
     ${!var[@]} |   F   |     T    |    T     | var is set

This table introduces the specification in the last row. The Bash manpage says "If name is not an array, expands to 0 if name is set and null otherwise." For purposes of this truth table, it behaves the same even if it's an array.

该表在最后一行介绍了规格。Bashman页面显示“如果 name 不是数组,则在设置 name 时扩展为 0,否则为 null。” 对于这个真值表,即使它是一个数组,它的行为也是一样的。

回答by lhunath

What you're looking for is indirection.

你正在寻找的是间接的。

assertNotEmpty() {
    : "${!1:? " is empty, aborting."}"
}

That causes the script to abort with an error message if you do something like this:

如果您执行以下操作,则会导致脚本中止并显示错误消息:

$ foo=""
$ assertNotEmpty foo
bash: !1:  foo is empty, aborting.

If you just want to testwhether foois empty, instead of aborting the script, use this instead of a function:

如果您只想测试是否foo为空,而不是中止脚本,请使用此代替函数:

[[ $foo ]]

For example:

例如:

until read -p "What is your name? " name && [[ $name ]]; do
    echo "You didn't enter your name.  Please, try again." >&2
done

Also, note that there is a very important differencebetween an emptyand an unsetparameter. You should take care not to confuse these terms! An empty parameter is one that is set but just set to an empty string. An unset parameter is one that doesn't exist at all.

另请注意,参数和未设置参数之间存在非常重要的区别。您应该注意不要混淆这些术语!空参数是已设置但仅设置为空字符串的参数。未设置的参数是根本不存在的参数。

The previous examples all test for emptyparameters. If you want to test for unsetparameters and consider all set parameters OK, whether they're empty or not, use this:

前面的例子都测试参数。如果要测试未设置的参数并认为所有设置的参数都正常,无论它们是否为空,请使用以下命令:

[[ ! $foo && ${foo-_} ]]

Use it in a function like this:

在这样的函数中使用它:

assertIsSet() {
    [[ ! ${!1} && ${!1-_} ]] && {
        echo " is not set, aborting." >&2
        exit 1
    }
}

Which only aborts the script when the parameter name you pass denotes a parameter that isn't set:

当您传递的参数名称表示未设置的参数时,它只会中止脚本:

$ ( foo="blah"; assertIsSet foo; echo "Still running." )
Still running.
$ ( foo=""; assertIsSet foo; echo "Still running." )
Still running.
$ ( unset foo; assertIsSet foo; echo "Still running." )
foo is not set, aborting.

回答by dnozay

You want to use [ -z ${parameter+word} ]

你想用 [ -z ${parameter+word} ]

Some part of man bash:

的某些部分man bash

Parameter Expansion
    ...
    In  each  of  the cases below, word is subject to tilde expansion, parameter expansion, command substitution, and
    arithmetic expansion.  When not performing substring expansion, bash tests for a parameter that is unset or null;
    omitting the colon results in a test only for a parameter that is unset.
    ...
    ${parameter:+word}
           Use Alternate Value.  If parameter is null or unset, nothing is substituted, otherwise  the  expansion  of
           word is substituted.
    ...

in other words:

换句话说:

    ${parameter+word}
           Use Alternate Value.  If parameter is unset, nothing is substituted, otherwise  the  expansion  of
           word is substituted.

some examples:

一些例子:

$ set | grep FOOBAR
$ if [ -z "${FOOBAR+something}" ]; then echo "it is unset"; fi
it is unset
$ declare FOOBAR
$ if [ -z "${FOOBAR+something}" ]; then echo "it is unset"; fi
$ FOOBAR=
$ if [ -z "${FOOBAR+something}" ]; then echo "it is unset"; fi
$ FOOBAR=1
$ if [ -z "${FOOBAR+something}" ]; then echo "it is unset"; fi
$ unset FOOBAR
$ if [ -z "${FOOBAR+something}" ]; then echo "it is unset"; fi
it is unset
$

回答by dnozay

This function tests for variables that ARE CURRENTLY set. The variable may even be an array. Note that in bash: 0 == TRUE, 1 == FALSE.

此函数测试当前设置的变量。变量甚至可能是一个数组。请注意,在 bash 中:0 == TRUE,1 == FALSE。

function var.defined {
    eval '[[ ${!''[@]} ]]'
}

# Typical Usage of var.defined {}

declare you="Your Name Here" ref='you';

read -p "What's your name: " you;

if var.defined you; then   # Simple demo using literal text

    echo "BASH recognizes $you";
    echo "BASH also knows a reference to $ref as ${!ref}, by indirection."; 

fi

unset you # have just been killed by a master :D

if ! var.defined $ref; then    # Standard demo using an expanded literal value

    echo "BASH doesn't know $ref any longer";

fi

read -s -N 1 -p "Press any key to continue...";
echo "";

So to be clear here, the function tests literal text. Everytime a command is called in bash, variables are GENERALLY 'swapped-out' or 'substituted' with the underlying value unless:

所以在这里要清楚,该函数测试文字文本。每次在 bash 中调用命令时,变量通常被“换出”或“替换”为基础值,除非:

  • $varRef ($) is escaped: \$varRef
  • $varRef is single quoted '$varRef'
  • $varRef ($) 被转义:\$varRef
  • $varRef 是单引号 '$varRef'

回答by Andrea Francia

I don't have understood exactly what do you need. I'm trying to replying you despite of this.

我不明白你到底需要什么。尽管如此,我还是想回复你。

I.e. I need to exit if the test fails.

即如果测试失败我需要退出。

The code:

编码:

${varName:?    "${varName} is not defined"}

will return a non zero exit code when there is not a variable named "varName". The exit code of the last command is saved in $?.

当没有名为“varName”的变量时,将返回一个非零退出代码。最后一条命令的退出代码保存在$?.

About your code:

关于你的代码:

val=${1:?    "    must be defined, preferably in $basedir"}

Maybe it is not doing what you need. In the case that $1is not defined the "${1}"will be substituted with nothing. Probably you want use the single quotes that literally writes ${1}without substitution.

也许它没有做你需要的。在$1未定义的情况下,"${1}"将被替换为空。可能你想使用${1}没有替换的字面意思的单引号。

val=${1:?    '    must be defined, preferably in $basedir'

回答by user381689

Unsure if this is exactly what you want but a handy trick I use when writing a new+complex script is to use "set -o"

不确定这是否正是您想要的,但我在编写新的+复杂脚本时使用的一个方便的技巧是使用“set -o”

set -o #will make the script bomb out when it finds an unset variable

set -o #将在找到未设置的变量时使脚本炸弹消失

EG:

例如:

$ grep '$1' chex.sh

case "$1" in

$ ./chex.sh

./chex.sh: line 111: $1: unbound variable

$ ./chex.sh foo

incorrect/no options passed.. exiting

$ grep '$1' chex.sh

案例“$1”在

$ ./chex.sh

./chex.sh:第 111 行:$1:未绑定变量

$ ./chex.sh foo

不正确/没有选项通过..退出

回答by Emery Lapinski

if set | grep -q '^VARIABLE='
then 
    echo VARIABLE is set
fi