【问题标题】:In Bash test if associative array is declared在 Bash 测试中是否声明了关联数组
【发布时间】:2015-01-11 14:28:43
【问题描述】:

如何测试是否在 Bash 中声明了关联数组?我可以测试如下变量:

[ -z $FOO ] && echo nope

但我似乎不适用于关联数组:

$ unset FOO
$ declare -A FOO
$ [ -z $FOO ] && echo nope
nope
$ FOO=([1]=foo)
$ [ -z $FOO ] && echo nope
nope
$ echo ${FOO[@]}
foo

编辑:

感谢您的回答,两者似乎都有效,所以我让速度决定:

$ cat test1.sh
#!/bin/bash
for i in {1..100000}; do
    size=${#array[@]}
    [ "$size" -lt 1 ] && :
done
$ time bash test1.sh #best of five

real    0m1.377s
user    0m1.357s
sys     0m0.020s

和其他:

$ cat test2.sh
#!/bin/bash

for i in {1..100000}; do
    declare -p FOO >/dev/null 2>&1 && :
done
$ time bash test2.sh #again, the best of five

real    0m2.214s
user    0m1.587s
sys     0m0.617s

编辑 2:

让我们快速比较一下 Chepner 的解决方案和之前的解决方案:

#!/bin/bash

for i in {1..100000}; do
    [[ -v FOO[@] ]] && :
done
$ time bash test3.sh #again, the best of five

real    0m0.409s
user    0m0.383s
sys     0m0.023s

嗯,这很快。

再次感谢各位。

【问题讨论】:

    标签: bash associative-array


    【解决方案1】:

    您可以使用declare -p 来检查变量是否已声明:

    declare -p FOO >/dev/null 2>&1 && echo "exists" || echo "nope"
    

    并专门检查关联数组:

    [[ "$(declare -p FOO 2>/dev/null)" == "declare -A"* ]] &&
       echo "array exists" || echo "nope"
    

    【讨论】:

    • 如果未设置变量,则不能使用declare -p检查变量是否已声明。
    • @Jani 不确定您在说什么。如果尚未设置变量,则声明将返回非零退出状态(与 help 命令声称的相反)。 @anubhava 在第二个示例中似乎有一个错字(我认为应该是 2>/dev/null)。否则,如果您想检测名称是否被声明为关联数组,这似乎是唯一有效的答案。
    • @RonBurk:感谢您的评论。 >/dev/null 2>&1 将 stdout 和 stderr 都重定向到 /dev/null 因此我们只能在此处处理退出代码。
    • @RonBurk 问题是如何检查变量是否已声明。如果您在 没有 设置值的情况下执行declare -A FOO,则不能使用declare -p 来测试是否已声明FOO。结果无法区分已声明和未声明。
    • 此解决方案有效。谢谢! (顺便说一句,“选择”的答案不...)
    【解决方案2】:

    最简单的方法之一是检查数组的大小:

    size=${#array[@]}
    [ "$size" -lt 1 ] && echo "array is empty or undeclared"
    

    您可以在命令行上轻松测试:

    $ declare -A ar=( [key1]=val1 [key2]=val2 ); echo "szar: ${#ar[@]}"
    szar: 2
    

    此方法允许您测试数组是否已声明和完全为空或未声明。空数组和未声明数组都将返回0 大小。

    【讨论】:

    • set -eu 加上${#array[@]} 导致以下错误array: unbound variable
    【解决方案3】:

    bash 4.2 或更高版本中,您可以使用-v 选项:

    [[ -v FOO[@] ]] && echo "FOO set"
    

    请注意,在任何版本中,使用

    declare -A FOO
    

    实际上并没有立即创建关联数组;它只是在名称FOO 上设置一个属性,允许您将其作为关联数组分配给该名称。在第一次赋值之前,数组本身并不存在。

    【讨论】:

    • 到目前为止,我无法找到上述代码中的“FOO[@]”可以产生与“FOO”不同的结果的任何情况。如果还打算检测 FOO 不是数组,我不知道有任何解决方案不需要使用declare(下面提供的数组大小检查没有帮助)。
    • 我猜一个足够新的 bash 可以通过使用 ${FOO@A} 来获得关于 FOO 的相同信息来避免 declare
    • 它不起作用。 $ declare -A FOO; [[ -v FOO[@] ]] && echo "FOO set" 从不运行“回声”。重击 4.4.x
    • @Kirby 因为FOO 没有设置;您所做的只是将数组属性添加到名称FOO。在您实际为数组赋值之前,它不会被设置(这是-v 测试的)。
    • 这并不能确定FOO 是否是一个关联数组——它也会以同样的方式返回一个数字索引的数组。
    【解决方案4】:

    这是 an excellent answer 的社区 Wiki 版本,由 @user15483624 提出,该问题现已作为重复而关闭。如果该用户选择在此处添加自己的答案,则应将其删除,以支持带有其姓名的答案。


    仅当需要与 bash 4.x 和先前版本兼容时,才应使用有关此问题的先前答案。在 bash 5.0 及更高版本中,可以直接使用检查变量类型的扩展;它的使用比解析declare -p 的输出要高效得多,并且它还避免了其他提案的一些意外副作用。..

    以下可用于测试bash变量是否为关联数组。

    [[ ${x@a} = A ]]
    

    ${x@a}可以用来判断是不是变量,也可以是数组。

    $ declare x; echo "${x@a}"
    
    $ declare -a y; echo "${y@a}"
    a
    $ declare -A z; echo "${z@a}"
    A
    

    【讨论】:

    • 请注意,即使未设置 x${x@a} 也会返回 A。然而,这允许构建一个存在某些密钥的安全测试:[[ ${x@a} = A && -v x[key] ]] && echo "x[key] is set"(也适用于set -u)。
    • @fuujuhi 你指的是哪个 Bash 版本?没有声明 x 或明确取消设置它:unset x; echo "${x@a}" 我得到空字符串,所以我无法确认你的陈述。 bash --version 在此处返回 5.0.17(1)-release。
    • @Cromax,如果我记得它是正确的上下文,来自 fuujuhi 的声明是指声明但未设置的情况,而不是未声明和未设置的情况。 (此外,这是“未设置”,如“从未分配过值”,而不是“有一个值,但它已被 unset 删除”)
    • @CharlesDuffy 你说得对,我的错。我想我太仓促了。无论如何,检查常规(非数组)变量是否已声明且未设置似乎是不可能的(declare -p 方法除外)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-07
    • 1970-01-01
    • 2020-04-11
    • 2013-01-30
    • 2018-02-24
    • 2010-11-12
    相关资源
    最近更新 更多