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

时间:2009-05-17 11:18:57

标签: bash variables undefined

一个简单的Bash变量测试:

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

我想通过把它放在一个函数中来重复使用它。 怎么样?

以下失败

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

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

7 个答案:

答案 0 :(得分:46)

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

    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.

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


                | 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

此表介绍了最后一行中的规范。 Bash man页面显示“如果name不是数组,如果设置了name,则展开为0,否则为null。”出于这个真值表的目的,即使它是一个数组,它的行为也是一样的。

答案 1 :(得分:19)

你正在寻找的是间接的。

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

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

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

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

[[ $foo ]]

例如:

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

另请注意,未设置参数之间存在非常重要的差异。你应该注意不要混淆这些条款!空参数是一个设置但只能设置为空字符串的参数。未设置的参数根本不存在。

前面的示例全部测试参数。如果您要测试未设置参数并考虑所有设置参数,无论它们是否为空,请使用以下命令:

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

在这样的函数中使用它:

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

只有在您传递的参数名称表示未设置的参数时才会中止脚本:

$ ( 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.

答案 2 :(得分:5)

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

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.
    ...
换句话说,

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

一些例子:

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

答案 3 :(得分:3)

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

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

# 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 "";

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

  • $ varRef($)被转义:\ $ varRef
  • $ varRef是单引号'$ varRef'

答案 4 :(得分:1)

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

  

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

代码:

${varName:?    "${varName} is not defined"}
当没有名为“varName”的变量时,

将返回非零退出代码。最后一个命令的退出代码保存在$?

关于您的代码:

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

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

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

答案 5 :(得分:1)

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

  

set -o #will会在找到未设置的变量

时弹出脚本炸弹

EG:

  

$ grep'$ 1'chex.sh

     

中的案例“$ 1”      

$ ./chex.sh

     

./ chex.sh:line 111:$ 1:未绑定的变量

     

$ ./chex.sh foo

     

错误/没有选项传递..退出

答案 6 :(得分:0)

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