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

#bash #hashmap

#bash #ассоциативный массив #ключ-значение #bash4

Вопрос:

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

 #!/bin/bash

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

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

Комментарии:

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

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

3. Аналог Zsh (спойлер: в Zsh все намного проще!): superuser.com/questions/737350 /…

4. @math Мне нравится простота этого, пожалуйста, подумайте о том, чтобы сделать это полноценным ответом

Ответ №1:

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

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

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

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

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

Комментарии:

1. Это теперь, если назначить все ключи массиву: array=(${!hash[@]})

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

3. @DennisWilliamson, большое спасибо. У меня этого не было в голове.

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

5. @pkaramol: Начиная с Bash 4.3, вы можете использовать ссылки на имена. Пример: 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 для получения некоторой важной информации.

Ответ №2:

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

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

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

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

Комментарии:

1. У меня было «!» — даже не заметил, не было ни одного, извините .. 🙂

2. echo "${!array[@]}" не сработало на моей машине. Я использую Mac.

Ответ №3:

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

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

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

3. Элегантное и лаконичное решение. Функциональное программирование FTW!

Ответ №4:

Добро пожаловать в input associative array 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!
  

Ответ №5:

 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
~