复杂的Bash结构

时间:2015-01-19 13:38:21

标签: bash dictionary

我正在尝试在bash中获取(键,多值)结构(某种类型的hashmap),如下所示:

[   
  [ "abc" : 1, 2, 3, 4 ],
  [ "def" : "w", 33, 2 ]    
]

我想遍历eack密钥(某种for key in ...),并使用map["def",2]map[$key,2]等内容获取每个值。

我见过几个关于单值hashmap的线程,但没有关于这个问题。

我可以使用N数组,N是我的地图中的键数量,填充连续的每个字段,但我不想尽可能多地复制代码。

提前致谢!

编辑: 我想通过这样的结构来完成结构:

for key in ${map[@]} do;
  echo $key # "abc" then "def"
  for value in ${map[$key,@]} do;
    ...
  done
done

2 个答案:

答案 0 :(得分:2)

在多阵列案例中使用现代bash功能:


作业(手册):

map_abc=( 1 2 3 4 )
map_def=( w 33 2 )

作业(程序化):

append() {
  local array_name="${1}_$2"; shift; shift
  declare -g -a "$array_name"
  declare -n array="$array_name" # BASH 4.3 FEATURE
  array+=( "$@" )
}
append map abc 1 2 3 4
append map def w 33 2

迭代(在函数内部完成,包含namevar' s范围):

iter() {
  for array in ${!map_@}; do
    echo "Iterating over array ${array#map_}"
    declare -n cur_array="$array" # BASH 4.3 FEATURE
    for key in "${!cur_array[@]}"; do
      echo "$key: ${cur_array[$key]}"
    done
  done
}
iter

这也可以在没有namevars的情况下完成,但是更丑陋,更容易出错。 (要清楚,我相信此处给出的代码安全地使用eval,但它很容易出错 - 如果尝试在此模板上构建自己的实现,请非常谨慎。)

# Compatible with older bash (should be through 3.x).
append() {
  local array_name="${1}_$2"; shift; shift
  declare -g -a "$array_name"

  local args_str cmd_str
  printf -v args_str '%q ' "$@"
  printf -v cmd_str "%q+=( %s )" "$array_name" "$args_str"
  eval "$cmd_str"
}

...并且,以与3.x相反的方式迭代迭代:

for array in ${!map_@}; do
  echo "Iterating over array ${array#map_}"

  printf -v cur_array_cmd 'cur_array=( ${%q[@]} )' "$array"
  eval "$cur_array_cmd"

  for key in "${!cur_array[@]}"; do
    echo "$key: ${cur_array[$key]}"
  done
done

这比通过单个大型数组进行过滤计算效率更高(给出的另一个答案) - 并且,当名称变量可用时,可以说代码也更清晰。

答案 1 :(得分:1)

DO-能。声明有点难看

declare -A map=(
    [abc,0]=1
    [abc,1]=2
    [abc,2]=3
    [abc,3]=4
    [def,0]=w
    [def,1]=33
    [def,2]=2
)
key="def"
i=1
echo "${map[$key,$i]}"   # => 33

迭代:有助于保留一个单独的"键":

keys=(abc def)

然后

for key in "${keys[@]}"; do 
    echo "$key"
    for idx in "${!map[@]}"; do 
        if [[ $idx == $key,* ]]; then 
            n=${idx##*,}
            printf "\t%s\t%s\n" "$n" "${map["$idx"]}"
        fi
    done
done
abc
    0   1
    1   2
    2   3
    3   4
def
    1   33
    0   w
    2   2