在 bash 的 key/value 对中迭代作为值嵌入的列表
Iterate over lists embedded as values in key/value pairs in bash
我正在尝试在 bash 中获取一个(键,多值)结构(某种哈希图),如下所示:
[
[ "abc" : 1, 2, 3, 4 ],
[ "def" : "w", 33, 2 ]
]
我想遍历每个键(某种 for key in ...
,并使用 map["def",2]
或 map[$key,2]
之类的东西获取每个值。
我看到几个线程在谈论单值哈希图,但没有提到这个问题。
我可以使用 N
数组,N
是我地图中键的数量,连续填充每个字段,但我不想重复代码可能。
提前致谢!
编辑:
我想通过这样的结构来完成:
for key in ${map[@]} do;
echo $key # "abc" then "def"
for value in ${map[$key,@]} do;
...
done
done
可行。声明有点难看
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":
的单独数组
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
在多数组情况下使用现代 bash 特征:
作业(手动):
map_abc=( 1 2 3 4 )
map_def=( w 33 2 )
作业(程序化):
append() {
local array_name="_"; 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 的范围):
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
这也可以在没有名称变量的情况下完成,但方式更丑陋且更容易出错。 (需要明确的是,我相信此处给出的代码可以安全地使用 eval
,但很容易出错——如果尝试在此模板上构建您自己的实现,请非常谨慎)。
# Compatible with older bash (should be through 3.x).
append() {
local array_name="_"; 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"
}
...并且,以与 bash 兼容的方式迭代回到 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
这比通过单个大数组过滤(给出的另一个答案)在计算上更有效 -- 而且,当 namevars 可用时,可以说也会产生更清晰的代码。
我正在尝试在 bash 中获取一个(键,多值)结构(某种哈希图),如下所示:
[
[ "abc" : 1, 2, 3, 4 ],
[ "def" : "w", 33, 2 ]
]
我想遍历每个键(某种 for key in ...
,并使用 map["def",2]
或 map[$key,2]
之类的东西获取每个值。
我看到几个线程在谈论单值哈希图,但没有提到这个问题。
我可以使用 N
数组,N
是我地图中键的数量,连续填充每个字段,但我不想重复代码可能。
提前致谢!
编辑: 我想通过这样的结构来完成:
for key in ${map[@]} do;
echo $key # "abc" then "def"
for value in ${map[$key,@]} do;
...
done
done
可行。声明有点难看
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":
的单独数组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
在多数组情况下使用现代 bash 特征:
作业(手动):
map_abc=( 1 2 3 4 )
map_def=( w 33 2 )
作业(程序化):
append() {
local array_name="_"; 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 的范围):
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
这也可以在没有名称变量的情况下完成,但方式更丑陋且更容易出错。 (需要明确的是,我相信此处给出的代码可以安全地使用 eval
,但很容易出错——如果尝试在此模板上构建您自己的实现,请非常谨慎)。
# Compatible with older bash (should be through 3.x).
append() {
local array_name="_"; 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"
}
...并且,以与 bash 兼容的方式迭代回到 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
这比通过单个大数组过滤(给出的另一个答案)在计算上更有效 -- 而且,当 namevars 可用时,可以说也会产生更清晰的代码。