Cómo iterar sobre matrices asociativas en Bash

351

Basado en una matriz asociativa en un script Bash, necesito iterar sobre él para obtener la clave y el valor.

#!/bin/bash

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

En realidad, no entiendo cómo obtener la clave mientras uso un bucle for-in.

pex
fuente
14
$ declare -A array = ([foo] = bar [bar] = foo) # Inicializa todo de una vez
anisbet
3
Para una pequeña lista de valores clave, puede considerar esto:for i in a,b c_s,d ; do KEY=${i%,*}; VAL=${i#*,}; echo $KEY" XX "$VAL; done
matemáticas

Respuestas:

582

Se accede a las claves mediante un signo de exclamación: se accede a ${!array[@]}los valores mediante ${array[@]}.

Puede iterar sobre los pares clave / valor de esta manera:

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

Tenga en cuenta el uso de comillas alrededor de la variable en la fordeclaración (más el uso de en @lugar de *). Esto es necesario en caso de que alguna clave incluya espacios.

La confusión en la otra respuesta proviene del hecho de que su pregunta incluye "foo" y "bar" tanto para las claves como para los valores.

Pausado hasta nuevo aviso.
fuente
3
Esto es ahora si asigna todas las claves a una matriz:array=(${!hash[@]})
Michael-O
12
@ Michael-O: debe citar la expansión de parámetros para proteger las claves que pueden tener espacios en blanco:array=("${!hash[@]}")
pausa hasta nuevo aviso.
@DennisWilliamson, muchas gracias. No tenía esto en mente.
Michael-O
¿Cómo podemos usar un número de argumento de función en lugar de una variable? por ejemplo for i in "${!$1[@]}"?
pkaramol
2
@pkaramol: a partir de Bash 4.3 puede usar namerefs. Ejemplo: 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. Consulte BashFAQ / 006 para obtener información importante.
Pausado hasta nuevo aviso.
42

Puede acceder a las teclas con ${!array[@]}:

bash-4.0$ echo "${!array[@]}"
foo bar

Luego, iterar sobre los pares clave / valor es fácil:

for i in "${!array[@]}"
do
  echo "key :" $i
  echo "value:" ${array[$i]}
done
tonio
fuente
1
Tuve el "!" - ni siquiera me di cuenta, no había ninguno, lo siento .. :)
pex
8

Usa esta función de orden superior para evitar la pirámide de la fatalidad

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

ejemplo:

$ bar(){ echo "$1 -> $2"; }
$ declare -A foo["flap"]="three four" foo["flop"]="one two"
$ foreach foo bar
flap -> three four
flop -> one two
coderofsalvación
fuente
1
No estoy seguro de cómo esto es aplicable? ¿No es la pirámide de la fatalidad un problema puramente estético y realmente solo aplicable en lenguajes orientados a objetos?
Alexej Magura
1
podrías explicarlo? La función foreach es un poco complicada. No lo entiendo
Bálint Szigeti
-1
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
~
EJISRHA
fuente