28

一个简单的 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
}

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

4

7 回答 7

46

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

    当不执行子字符串扩展时,bash 测试一个参数
    未设置或为空;省略冒号会导致仅对参数进行测试
    三是未设置。

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

                | 未设置 | 设置 | 设置和 | 意义
                | | 但为空| 不为空 |
    ============+========+===========+==========+======= =======================
     ${var-_} | T | F | T | 不为空或未设置
    ------------+--------+----------+----------+-------- ----------------------
     ${var:-_} | T | T | T | 总是正确的,用于替代。
    ------------+--------+----------+----------+-------- ----------------------
     $变量 | F | F | T | var 已设置且不为空
    ------------+--------+----------+----------+-------- ----------------------
     ${!var[@]} | F | T | T | var 已设置

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

于 2009-09-24T02:04:30.513 回答
19

您正在寻找的是间接性。

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

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

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

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

[[ $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.
于 2009-05-17T12:36:17.467 回答
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
于 2012-11-26T19:35:23.797 回答
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'
于 2011-05-15T02:09:05.323 回答
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'
于 2009-05-17T12:02:35.257 回答
1

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

set -o #当它发现一个未设置的变量时,会使脚本炸弹

例如:

$ grep '$1' chex.sh

案例“$1”在

$ ./chex.sh

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

$ ./chex.sh 富

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

于 2010-11-06T00:54:14.540 回答
0
if set | grep -q '^VARIABLE='
then
    echo VARIABLE is set
fi
于 2014-06-01T07:40:27.903 回答