Como iterar sobre matrizes associativas no Bash

351

Com base em uma matriz associativa em um script Bash, preciso iterar sobre ela para obter a chave e o valor.

#!/bin/bash

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

Na verdade, eu não entendo como obter a chave enquanto estiver usando um loop for-in.

pex
fonte
14
$ declare -A array = ([foo] = bar [bar] = foo) # Inicialize tudo de uma vez
anisbet
3
Por uma pequena lista de valores-chave que você pode considerar o seguinte:for i in a,b c_s,d ; do KEY=${i%,*}; VAL=${i#*,}; echo $KEY" XX "$VAL; done
matemática

Respostas:

582

As chaves são acessadas usando um ponto de exclamação:, ${!array[@]}os valores são acessados ​​usando ${array[@]}.

Você pode iterar sobre os pares chave / valor como este:

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

Observe o uso de aspas ao redor da variável na forinstrução (mais o uso de em @vez de *). Isso é necessário caso alguma chave inclua espaços.

A confusão na outra resposta vem do fato de sua pergunta incluir "foo" e "bar" para as chaves e os valores.

Pausado até novo aviso.
fonte
3
Agora, se você atribuir todas as chaves a uma matriz:array=(${!hash[@]})
Michael-O
12
@ Michael-O: Você precisa citar a expansão do parâmetro para proteger as chaves que podem ter espaços em branco:array=("${!hash[@]}")
Pausado até novo aviso.
@DennisWilliamson, muito obrigado. Eu não tinha isso em mente.
Michael-O
Como podemos usar um número de argumento de função em vez de uma variável? por exemplo for i in "${!$1[@]}"?
Pkaramol
2
@pkaramol: A partir do Bash 4.3, você pode usar o namerefs. Exemplo: 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 o BashFAQ / 006 para obter algumas informações importantes.
Pausado até novo aviso.
42

Você pode acessar as chaves com ${!array[@]}:

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

Então, é fácil iterar sobre os pares chave / valor:

for i in "${!array[@]}"
do
  echo "key :" $i
  echo "value:" ${array[$i]}
done
tonio
fonte
11
Eu tinha o "!" - nem percebi, não havia, desculpe .. :)
pex
8

Use esta função de ordem superior para evitar a pirâmide da desgraça

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

exemplo:

$ bar(){ echo "$1 -> $2"; }
$ declare -A foo["flap"]="three four" foo["flop"]="one two"
$ foreach foo bar
flap -> three four
flop -> one two
coderofsalvation
fonte
11
Não tenho certeza de como isso é aplicável. A pirâmide da desgraça não é uma questão puramente estética e realmente aplicável apenas em linguagens orientadas a objetos?
Alexej Magura
11
você poderia explicar isso? A função foreach é um pouco complicada. Eu não entendo.
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
fonte