Jak iterować po tablicach asocjacyjnych w Bash

351

Opierając się na tablicy asocjacyjnej w skrypcie Bash, muszę iterować, aby uzyskać klucz i wartość.

#!/bin/bash

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

Właściwie nie rozumiem, jak zdobyć klucz podczas korzystania z pętli for-in.

pex
źródło
14
$ deklarre -A array = ([foo] = bar [bar] = foo) # Zainicjuj wszystko naraz
anisbet
3
W przypadku małej listy kluczowych wartości można rozważyć:for i in a,b c_s,d ; do KEY=${i%,*}; VAL=${i#*,}; echo $KEY" XX "$VAL; done
matematyka

Odpowiedzi:

581

Dostęp do kluczy można uzyskać za pomocą wykrzyknika: dostęp ${!array[@]}do wartości można uzyskać za pomocą ${array[@]}.

Możesz iterować po parach klucz / wartość w następujący sposób:

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

Zwróć uwagę na użycie cudzysłowu wokół zmiennej w forinstrukcji (plus użycie @zamiast zamiast *). Jest to konieczne w przypadku, gdy dowolny klawisz zawiera spacje.

Zamieszanie w drugiej odpowiedzi wynika z faktu, że twoje pytanie zawiera „foo” i „bar” zarówno dla kluczy, jak i wartości.

Wstrzymano do odwołania.
źródło
3
Jest to teraz, jeśli przypisz wszystkie klucze do tablicy:array=(${!hash[@]})
Michael-O
12
@ Michael-O: Musisz zacytować rozszerzenie parametru, aby chronić klucze, które mogą mieć spacje:array=("${!hash[@]}")
Wstrzymano do odwołania.
@DennisWilliamson, wielkie dzięki. Nie miałem tego na myśli.
Michael-O,
Jak możemy użyć numeru argumentu funkcji zamiast zmiennej? na przykład for i in "${!$1[@]}"?
pkaramol
2
@pkaramol: Począwszy od wersji Bash 4.3 możesz używać nazw. Przykład: 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. Zobacz BashFAQ / 006, aby uzyskać ważne informacje.
Wstrzymano do odwołania.
42

Możesz uzyskać dostęp do klawiszy za pomocą ${!array[@]}:

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

Następnie iteracja par klucz / wartość jest łatwa:

for i in "${!array[@]}"
do
  echo "key :" $i
  echo "value:" ${array[$i]}
done
tonio
źródło
1
Miałem "!" - nawet nie zauważyłem, nie było, przepraszam .. :)
pex
8

Użyj tej funkcji wyższego rzędu, aby zapobiec piramidie zagłady

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

przykład:

$ bar(){ echo "$1 -> $2"; }
$ declare -A foo["flap"]="three four" foo["flop"]="one two"
$ foreach foo bar
flap -> three four
flop -> one two
coderofsalvation
źródło
1
Nie jestem pewien, jak to się stosuje? Czy piramida zagłady nie jest kwestią czysto estetyczną i naprawdę można ją stosować tylko w językach obiektowych?
Alexej Magura
1
mógłbyś to wyjaśnić? Funkcja Foreach jest nieco trudna. Nie rozumiem
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
źródło