Как перебрать ассоциативные массивы в Bash


351

Основываясь на ассоциативном массиве в скрипте Bash, мне нужно перебрать его, чтобы получить ключ и значение.

#!/bin/bash

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

Я на самом деле не понимаю, как получить ключ при использовании цикла for-in.


14
$ Declare -A array = ([foo] = bar [bar] = foo) # Инициализировать все сразу
anisbet

3
Для небольшого списка ключевых значений вы можете рассмотреть это:for i in a,b c_s,d ; do KEY=${i%,*}; VAL=${i#*,}; echo $KEY" XX "$VAL; done
математика

Ответы:


582

Ключи доступны с помощью восклицательного знака: ${!array[@]}, то значения доступны при использовании ${array[@]}.

Вы можете перебирать пары ключ / значение следующим образом:

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

Обратите внимание на использование кавычек вокруг переменной в forвыражении (плюс использование @вместо *). Это необходимо в случае, если какие-либо ключи содержат пробелы.

Путаница в другом ответе связана с тем, что ваш вопрос включает в себя «foo» и «bar» как для ключей, так и для значений.


3
Это теперь, если назначить все ключи для массива:array=(${!hash[@]})
Michael-O

12
@ Michael-O: Вы должны указать расширение параметра в кавычках, чтобы защитить ключи, которые могут иметь пробелы:array=("${!hash[@]}")
Приостановлено до дальнейшего уведомления.

@DennisWilliamson, спасибо большое. Я не думал об этом.
Майкл-О

Как мы можем использовать номер аргумента функции вместо переменной? например for i in "${!$1[@]}"?
пкарамол

2
@pkaramol: Начиная с 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 для получения важной информации.
Приостановлено до дальнейшего уведомления.

42

Вы можете получить доступ к ключам с помощью ${!array[@]}:

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

Затем легко выполнить итерации по парам ключ / значение:

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

1
У меня было "!" - даже не заметил, не было, извините .. :)
pex

8

Используйте эту функцию более высокого порядка, чтобы предотвратить пирамиду гибели

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
Я не уверен, как это применимо? Разве пирамида гибели не является чисто эстетической проблемой и действительно применима только в объектно-ориентированных языках?
Алексей Магура

1
не могли бы вы объяснить это? Функция foreach немного сложна. Я не понимаю
Балинт Сигети

-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
~
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.