【问题标题】:Using unset vs. setting a variable to empty使用未设置与将变量设置为空
【发布时间】:2012-08-29 01:35:57
【问题描述】:

我目前正在编写一个 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=''

哪个更好?它真的有区别吗?或者也许我应该有一个额外的标志来指示消息已设置?

【问题讨论】:

  • 如果你从不将error_message 与其他任何东西进行比较,我会说没关系。但是,我认为您想要[[ $error_message ]],否则您正在测试文字字符串“error_message”是否存在。
  • @chepner 是的,是一个错字。修好了。

标签: bash variables syntax


【解决方案1】:

除非您使用的是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

【讨论】:

  • var= 不是“未设置”。它只是一个未加引号的空字符串。除了set -u之外,bash的各种形式的参数扩展也可以区分unset和null值:${foo:bar}foo未设置时扩展为“bar”,但foo为null时扩展为“”,而@987654330如果 foo 未设置或为空,@ 扩展为 "bar"。
  • 如果var 设置为空字符串,[[ -n $var ]] 为 false。
  • 如果你使用 'declare -p' 来检查变量 'existence' 那么 var= 将显示 'declare -- var=""' 你必须使用 unset 来摆脱它,当然如果它是一个只读变量,那么你当然不能摆脱它。此外,如果你 var=something 在函数内部,你不必担心如果你使用“local var=value”来摆脱它,但要小心,因为“declare var=value”也是本地的。在声明的情况下您必须使用“declare -g var=value”将其显式设置为全局,而无需声明,您必须使用“local”将其显式设置为本地。全局变量仅被擦除/w unset。
  • @osirisgothra:关于局部变量的要点。当然,通常最好在函数中声明(或本地化)所有变量,以便对其进行封装。
  • @chepner 应该是 ${foo-bar} 而不是 ${foo:bar}。自己测试:unset a; echo ">${a:-foo}-${a:foo}-${a-foo}<"
【解决方案2】:

如前所述,使用 unset 与数组不同

$ foo=(4 5 6)

$ foo[2]=

$ echo ${#foo[*]}
3

$ unset foo[2]

$ echo ${#foo[*]}
2

【讨论】:

    【解决方案3】:

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

    我自己做了测试..

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

    这会导致..

    3
    0
    

    所以只是为了澄清取消设置整个数组实际上会完全删除它。

    【讨论】:

      【解决方案4】:

      根据上面的cmets,这里做一个简单的测试:

      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
      

      【讨论】:

        猜你喜欢
        • 2012-11-07
        • 2011-01-03
        • 2019-06-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多