【问题标题】:Iterating over list of arrays in bash迭代bash中的数组列表
【发布时间】:2016-06-03 06:09:17
【问题描述】:

我需要在 bash 中迭代几个键值数组(关联数组)。这是我的最后一次尝试:

declare -A ARR1
ARR1[foo]=bar

declare -A ARR2
ARR2[foo]=baz

arrays=(ARR1 ARR2)

for idx in "${arrays[@]}"; do
    echo ${${idx}[foo]};
done 

这当然是错误的(语法错误),但此时我没有其他想法如何处理它。而在下面的示例中没有错误,但输出只是一个数组的名称。

for idx in "${array[@]}"; do
    echo "${idx[foo]}";
done

------- OUTPUT -------
ARR1
ARR2

编辑

好的,我可以通过使用eval

eval echo \${${idx}[foo]};

但是,我读到在 bash 脚本中使用 eval 并不是一个好主意。有没有更好的办法?

【问题讨论】:

    标签: arrays bash associative-array


    【解决方案1】:

    Bash 4.3-alpha 引入了nameref attribute,可以在这种情况下使用:

    declare -A arr1=([foo]=bar)
    declare -A arr2=([foo]=baz)
    arrays=(arr1 arr2)
    
    for idx in "${arrays[@]}"; do
        declare -n temp="$idx"
        echo "${temp[foo]}"
    done
    

    给出输出

    bar
    baz
    

    正如kojiro 在他的评论中指出的那样,只要名称具有共享前缀,实际上并不需要将数组名称存储在数组中以进行迭代。

    arrays=(arr1 arr2)
    
    for idx in "${arrays[@]}"; do
    

    可以替换为

    for idx in "${!arr@}"; do
    

    请注意,尽管有感叹号,但这与间接扩展无关。


    参考手册的相关摘录

    Shell Parameters”部分:

    可以使用-n 为变量分配nameref 属性 declarelocal 内置命令的选项(请参阅 Bash Builtins) 创建一个nameref,或对另一个变量的引用。这允许 间接操纵的变量。每当 nameref 变量 被引用或分配给,操作实际上是在 nameref 变量的值指定的变量。 nameref 是 通常在 shell 函数中用于引用其名称的变量 作为参数传递给函数。例如,如果一个变量 name 作为第一个参数传递给 shell 函数,运行

    declare -n ref=$1
    

    在函数内部创建一个nameref变量ref,其值为 作为第一个参数传递的变量名。参考文献和 对ref 的分配被视为对 名称作为 $1 传递的变量。

    如果for 循环中的控制变量具有nameref 属性,则 单词列表可以是 shell 变量列表和名称引用 将依次为列表中的每个单词建立循环时 被执行。数组变量不能被赋予-n 属性。 但是,nameref 变量可以引用数组变量和 下标数组变量。可以使用 -n 取消设置 Namerefs unset 内置选项(请参阅Bourne Shell Builtins)。 否则,如果使用 nameref 变量的名称执行 unset 作为参数,nameref 变量引用的变量将 取消设置。

    Shell Parameter Expansion”部分:

    ${!前缀*}
    ${!前缀@}

    扩展到名称以 prefix 开头的变量的名称, 由IFS 特殊变量的第一个字符分隔。什么时候 使用@,扩展出现在双引号内,每个 变量名扩展为一个单独的单词。

    【讨论】:

    • 不必将数组的名称保存在另一个数组中——只要它们具有唯一的名称pattern,您就可以这样引用它们。在这种情况下,类似于${!arr*}
    • 这不是和@ffledgling 提供的选项一样,而是采用内置bash 的形式吗?
    • @kashpersky 它们相似,但不一样。上面提到的mywiki.wooledge.org/BashFAQ/006 谈到了其中的一些。 Namerefs 是正确的引用,例如,可以用于更轻松地处理数组作为函数中的位置参数。
    • 谢谢@kojiro。 ${!arr@} 完成了这项工作:)
    • Namerefs 实际上在那篇博文中被简单地提到过。
    【解决方案2】:

    您可以像使用间接替换一样执行此操作,但理想情况下,如果它不是一次性脚本,您不希望将 bash 用于此类操作。

    #!/bin/bash
    set -ex
    
    declare -A ARR1
    ARR1[foo]=bar
    
    declare -A ARR2
    ARR2[foo]=baz
    
    arrays=(ARR1 ARR2)
    
    for idx in "${arrays[@]}"; do
      x="${idx}[foo]" # Store as a string in a variable
      echo ${!x} # Reference using indirection.
    done 
    

    请参阅http://mywiki.wooledge.org/BashFAQ/006 了解更多信息。

    【讨论】:

      猜你喜欢
      • 2012-08-07
      • 2021-12-04
      • 1970-01-01
      • 2014-03-25
      • 2017-07-02
      • 2016-07-19
      • 1970-01-01
      • 2018-03-01
      • 1970-01-01
      相关资源
      最近更新 更多