如何在Bash中遍历关联数组

449

在Bash脚本中,基于一个关联数组,我需要对其进行迭代以获取键和值。

#!/bin/bash

declare -A array
array[foo]=bar
array[bar]=foo

实际上我不明白如何在使用for-in循环时获取键(key)。


24
声明一个关联数组,其中 [foo] 的值为 "bar",[bar] 的值为 "foo"。使用一次性初始化方式完成。原始代码为:$ declare -A array=( [foo]=bar [bar]=foo )。 - anisbet
4
对于一个小的键值列表,您可以考虑使用以下命令:for i in a,b c_s,d; do KEY=${i%,*}; VAL=${i#*,}; echo $KEY" XX "$VAL; done。该命令会输出每个键和对应的值,中间用“XX”分隔。请注意,如果您需要添加更多的键值对,请按照相同的格式在列表中添加它们。 - math
Zsh的对应项(提示:在Zsh中要简单得多!):https://superuser.com/questions/737350/iterating-over-keys-or-k-v-pairs-in-zsh-associative-array - Franklin Yu
@math 我喜欢它的简洁性,请考虑将其作为完整的回复。 - Maxim Ky
5个回答

720

通过感叹号(!)访问键:${!array[@]}可以使用${array[@]}来访问。

您可以像这样迭代键/值对:

for i in "${!array[@]}"
do
  echo "key  : $i"
  echo "value: ${array[$i]}"
done

请注意,在for循环语句中将变量用引号括起来(同时使用@而不是*)。这是必要的,以防任何键包含空格。

其他答案中的混淆在于您的问题包括键和值的“foo”和“bar”。


4
如果将所有键分配给一个数组,代码如下:array=(${!hash[@]}) - Michael-O
17
@Michael-O:你需要引用参数替换语法保护可能包含空格的键:array=("${!hash[@]}") - Dennis Williamson
1
我们如何使用函数参数数字而不是变量?例如:for i in "${!$1[@]}" - pkaramol
4
从Bash 4.3开始,您可以使用名称引用(namerefs)。例如:declare -A aa; aa['A']=a1; aa['B']=b2; aa['C']=c3; foo () { declare -n assoc=$1; for key in "${!assoc[@]}"; do echo "Key: $key; Value: ${assoc[$key]}"; done; }; foo aa。请参阅BashFAQ/006获取一些重要信息。 - Dennis Williamson
这可以在哪里找到参考资料,或者这是来自man页面吗?我正在查看高级Bash脚本指南,但发现很难获得简明的信息。它甚至没有提到关联数组。好的,我在man bash中找到了这些信息。 - Werner Erasmus
显示剩余2条评论

63
你可以使用${!array[@]}来访问键:
bash-4.0$ echo "${!array[@]}"
foo bar

然后,遍历键/值对很容易:

for i in "${!array[@]}"
do
  echo "key :" $i
  echo "value:" ${array[$i]}
done

1
我加了个 "!" - 没注意到其实不需要,抱歉.. :) - pex
1
我的机器上无法使用 echo "${!array[@]}" 命令。我正在使用 Mac。 - MA1
我也注意到了这个问题:它在我的Linux上可以运行(使用的是bash版本4.4.20),但在Mac上却不行(使用的是bash版本3.2.57)... - plijnzaad

13

使用这个高阶函数来避免毁灭金字塔

foreach(){ 
  arr="$(declare -p $1)" ; eval "declare -A f="${arr#*=}; 
  for i in ${!f[@]}; do $2 "$i" "${f[$i]}"; done
}

例子:

$ bar(){ echo "$1 -> $2"; }
$ declare -A foo["flap"]="three four" foo["flop"]="one two"
$ foreach foo bar
flap -> three four
flop -> one two

1
我不确定这有什么用?金字塔式的恶魔是一个纯粹的美学问题,只适用于面向对象的编程语言,不是吗? - Alexej Magura
1
能否解释一下吗?foreach函数有点棘手,我不太明白。 - Bálint Szigeti
优雅简洁的解决方案。函数式编程万岁! - Olivier Gérardin

5

欢迎使用关联输入数组 2.0!

    clear
    echo "Welcome to input associative array 2.0! (Spaces in keys and values now supported)"
    unset array
    declare -A array
    read -p 'Enter number for array size: ' num
    for (( i=0; i < num; i++ ))
        do
            echo -n "(pair $(( $i+1 )))"
            read -p ' Enter key: ' k
            read -p '         Enter value: ' v
            echo " "
            array[$k]=$v
        done
    echo " "
    echo "The keys are: " ${!array[@]}
    echo "The values are: " ${array[@]}
    echo " "
    echo "Key <-> Value"
    echo "-------------"
    for i in "${!array[@]}"; do echo $i "<->" ${array[$i]}; done
    echo " "
    echo "Thanks for using input associative array 2.0!"

输出:

Welcome to input associative array 2.0! (Spaces in keys and values now supported)
Enter number for array size: 4
(pair 1) Enter key: Key Number 1
         Enter value: Value#1

(pair 2) Enter key: Key Two
         Enter value: Value2

(pair 3) Enter key: Key3
         Enter value: Val3

(pair 4) Enter key: Key4
         Enter value: Value4


The keys are:  Key4 Key3 Key Number 1 Key Two
The values are:  Value4 Val3 Value#1 Value2

Key <-> Value
-------------
Key4 <-> Value4
Key3 <-> Val3
Key Number 1 <-> Value#1
Key Two <-> Value2

Thanks for using input associative array 2.0!

输入关联数组 1.0

(不支持包含空格的键名和值)

    clear
    echo "Welcome to input associative array! (written by mO extraordinaire!)"
    unset array
    declare -A array
    read -p 'Enter number for array size: ' num
    for (( i=0; i < num; i++ ))
        do
            read -p 'Enter key and value separated by a space: ' k v
            array[$k]=$v
        done
    echo " "
    echo "The keys are: " ${!array[@]}
    echo "The values are: " ${array[@]}
    echo " "
    echo "Key <-> Value"
    echo "-------------"
    for i in ${!array[@]}; do echo $i "<->" ${array[$i]}; done
    echo " "
    echo "Thanks for using input associative array!"

输出:

Welcome to input associative array! (written by mO extraordinaire!)
Enter number for array size: 10
Enter key and value separated by a space: a1 10
Enter key and value separated by a space: b2 20
Enter key and value separated by a space: c3 30
Enter key and value separated by a space: d4 40
Enter key and value separated by a space: e5 50
Enter key and value separated by a space: f6 60
Enter key and value separated by a space: g7 70
Enter key and value separated by a space: h8 80
Enter key and value separated by a space: i9 90
Enter key and value separated by a space: j10 100

The keys are:  h8 a1 j10 g7 f6 e5 d4 c3 i9 b2
The values are:  80 10 100 70 60 50 40 30 90 20

Key <-> Value
-------------
h8 <-> 80
a1 <-> 10
j10 <-> 100
g7 <-> 70
f6 <-> 60
e5 <-> 50
d4 <-> 40
c3 <-> 30
i9 <-> 90
b2 <-> 20

Thanks for using input associative array!

-2
declare -a arr
echo "-------------------------------------"
echo "Here another example with arr numeric"
echo "-------------------------------------"
arr=( 10 200 3000 40000 500000 60 700 8000 90000 100000 )

echo -e "\n Elements in arr are:\n ${arr[0]} \n ${arr[1]} \n ${arr[2]} \n ${arr[3]} \n ${arr[4]} \n ${arr[5]} \n ${arr[6]} \n ${arr[7]} \n ${arr[8]} \n ${arr[9]}"

echo -e " \n Total elements in arr are : ${arr[*]} \n"

echo -e " \n Total lenght of arr is : ${#arr[@]} \n"

for (( i=0; i<10; i++ ))
do      echo "The value in position $i for arr is [ ${arr[i]} ]"
done

for (( j=0; j<10; j++ ))
do      echo "The length in element $j is ${#arr[j]}"
done

for z in "${!arr[@]}"
do      echo "The key ID is $z"
done
~

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接