Làm thế nào để lặp lại các mảng kết hợp trong Bash


351

Dựa trên một mảng kết hợp trong tập lệnh Bash, tôi cần lặp lại nó để lấy khóa và giá trị.

#!/bin/bash

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

Tôi thực sự không hiểu làm thế nào để lấy chìa khóa trong khi sử dụng vòng lặp for-in.


14
$ khai báo -A mảng = ([foo] = bar [bar] = foo) # Khởi tạo tất cả cùng một lúc
đĩa mềm

3
Đối với một danh sách nhỏ các giá trị chính, bạn có thể xem xét điều này:for i in a,b c_s,d ; do KEY=${i%,*}; VAL=${i#*,}; echo $KEY" XX "$VAL; done
toán

Câu trả lời:


582

Các khóa được truy cập bằng dấu chấm than : ${!array[@]}, các giá trị được truy cập bằng ${array[@]}.

Bạn có thể lặp lại các cặp khóa / giá trị như thế này:

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

Lưu ý việc sử dụng dấu ngoặc kép quanh biến trong forcâu lệnh (cộng với việc sử dụng @thay vì *). Điều này là cần thiết trong trường hợp bất kỳ khóa bao gồm không gian.

Sự nhầm lẫn trong câu trả lời khác xuất phát từ thực tế là câu hỏi của bạn bao gồm "foo" và "bar" cho cả khóa giá trị.


3
Bây giờ là nếu gán tất cả các khóa cho một mảng:array=(${!hash[@]})
Michael-O

12
@ Michael-O: Bạn cần trích dẫn việc mở rộng tham số để bảo vệ các khóa có thể có khoảng trắng:array=("${!hash[@]}")
Tạm dừng cho đến khi có thông báo mới.

@DennisWilliamson, cảm ơn rất nhiều. Tôi đã không có điều này trong tâm trí của tôi.
Michael-O

Làm thế nào chúng ta có thể sử dụng một số đối số chức năng thay vì một biến? ví dụ for i in "${!$1[@]}"?
pkaramol

2
@pkaramol: Bắt đầu từ Bash 4.3, bạn có thể sử dụng bảng tên. Ví dụ : 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. Vui lòng xem BashFAQ / 006 để biết một số thông tin quan trọng.
Tạm dừng cho đến khi có thông báo mới.

42

Bạn có thể truy cập các phím bằng ${!array[@]}:

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

Sau đó, việc lặp lại các cặp khóa / giá trị rất dễ dàng:

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

1
Tôi đã có "!" - thậm chí không nhận thấy, không có ai, xin lỗi .. :)
pex

8

Sử dụng chức năng bậc cao này để ngăn chặn kim tự tháp diệt vong

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

thí dụ:

$ bar(){ echo "$1 -> $2"; }
$ declare -A foo["flap"]="three four" foo["flop"]="one two"
$ foreach foo bar
flap -> three four
flop -> one two

1
Tôi không chắc làm thế nào điều này được áp dụng? Không phải kim tự tháp của sự diệt vong là một vấn đề hoàn toàn về mặt thẩm mỹ và thực sự chỉ có thể áp dụng trong các ngôn ngữ hướng đối tượng?
Alexej Magura

1
bạn có thể giải thích nó? Hàm foreach hơi phức tạp. Tôi không hiểu
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
~
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.