使用未设置与将变量设置为空


108

我目前正在编写bash测试框架,在该框架中的测试功能中,可以使用标准bash测试([[)和预定义的匹配器。匹配器是'[['的包装器,除了返回返回代码外,还设置一些有意义的消息以说明期望的内容。

例:

string_equals() {
    if [[ ! $1 = $2 ]]; then
            error_message="Expected '$1' to be '$2'."

            return 1
    fi
}

因此,当使用匹配器而失败时,仅设置error_message。

现在,在以后的某个时刻,我测试测试是否成功。如果成功,则将期望打印为绿色,如果失败,则将打印为红色。

此外,可能设置了error_message,所以我测试消息是否存在,打印出来,然后取消设置(因为以下测试可能没有设置error_message):

if [[ $error_message ]]; then
    printf '%s\n' "$error_message"

    unset -v error_message
fi

现在我的问题是,是否最好取消设置变量,或者只是将其设置为“

error_message=''

哪一个更好?它实际上有区别吗?还是我应该有一个附加标志来指示已设置该消息?


1
如果您从未error_message与其他任何东西进行比较,我会说这没关系。但是,我认为您想要[[ $error_message ]],否则您正在测试文字字符串“ error_message”是否存在。
chepner 2012年

@chepner是的,是一个错字。解决它。
helpermethod 2012年

Answers:


143

通常情况下,除非您正在使用set -u

/home/user1> var=""
/home/user1> echo $var

/home/user1> set -u
/home/user1> echo $var

/home/user1> unset var
/home/user1> echo $var
-bash: var: unbound variable

因此,实际上,这取决于您如何测试变量。

我将添加我的首选测试方式(如果已设置)是:

[[ -n $var ]]  # True if the length of $var is non-zero

要么

[[ -z $var ]]  # True if zero length

43
var=不是“未设置”。这只是一个没有引号的空字符串。除了set -u,bash的各种参数扩展形式还可以区分未设置值和null值:未设置${foo:bar}时扩展为“ bar” foo,但foo为null时${foo:-bar}扩展为“ bar” ,而如果foo未设置或为null则扩展为“ bar”。
chepner 2012年

1
[[ -n $var ]]如果var设置为空字符串,则为false 。
chepner 2012年

1
如果您使用'declare -p'检查变量'existence',则var =将显示'declare-var =“”',您必须使用unset摆脱它,当然,如果它是一个只读变量,那么您将无法获取当然要摆脱它。此外,如果您在函数内部使用var = something,则不必担心如果使用“ local var = value”会摆脱它,因为“ declare var = value”也是局部的。您必须使用“ declare -g var = value”将其全局设置为显式,而无需声明,您必须使用“ local”将其显式设置为本地。仅删除/ w未设置全局变量。
osirisgothra 2014年

@osirisgothra:关于局部变量的要点。当然,通常最好在函数中声明(或本地化)所有变量,以便对其进行封装。
cdarke

3
@chepner应该${foo-bar}代替${foo:bar}。为自己测试:unset a; echo ">${a:-foo}-${a:foo}-${a-foo}<"
Liviu Chircu

17

如前所述,数组使用unset的方式也不同

$ foo=(4 5 6)

$ foo[2]=

$ echo ${#foo[*]}
3

$ unset foo[2]

$ echo ${#foo[*]}
2

2

因此,通过取消设置数组索引2,实际上可以删除数组中的该元素并减小数组大小(?)。

我做了自己的测试。

foo=(5 6 8)
echo ${#foo[*]}
unset foo
echo ${#foo[*]}

结果是..

3
0

因此,为了澄清一下,取消设置整个数组实际上会完全删除它。


0

根据上面的评论,这是一个简单的测试:

isunset() { [[ "${!1}" != 'x' ]] && [[ "${!1-x}" == 'x' ]] && echo 1; }
isset()   { [ -z "$(isunset "$1")" ] && echo 1; }

例:

$ unset foo; [[ $(isunset foo) ]] && echo "It's unset" || echo "It's set"
It's unset
$ foo=     ; [[ $(isunset foo) ]] && echo "It's unset" || echo "It's set"
It's set
$ foo=bar  ; [[ $(isunset foo) ]] && echo "It's unset" || echo "It's set"
It's set
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.