Mảng liên kết trong Shell Script


10

Tôi đã thấy một mẹo để thực hiện các mảng kết hợp trong một kịch bản shell. Ví dụ print array["apples"]có thể được viết theo kịch bản là echo \$array$keynơi key = apple.

Tuy nhiên, không có đề cập đến cách tạo các khóa để lặp qua mảng. Cách duy nhất tôi có thể nghĩ đến là lưu trữ các khóa trong một biến được phân tách bằng khoảng trắng để tôi có thể sử dụng vòng lặp for để lặp qua mảng.

Vì vậy, có một số cách khác để lưu trữ các phím để sử dụng sau?


5
Nếu bạn đang cố gắng sử dụng các mảng kết hợp trong tập lệnh shell thì có thể dự án của bạn quá phức tạp đối với tập lệnh shell :)
Martin von Wittich

@MartinvonWittich tại sao? Tôi có một tập lệnh shell thực thi tập lệnh SQL trên một trong 3 lược đồ DB có thể. Các lược đồ cần thiết được bao gồm trong tên tệp với một chữ viết tắt. Tôi cần một ánh xạ giữa chữ viết tắt này và tên lược đồ thực. Cách nào tốt hơn một mảng kết hợp, xem xét các tên lược đồ thực tế (không phải viết tắt) có thể khác nhau giữa các môi trường, do đó, một biến mảng (có thể đặt giá trị chỉ một lần) là hoàn hảo
Slav

2
@Slav Tôi không tranh cãi với các mảng kết hợp, chỉ chống lại các kịch bản shell khi cần sự phức tạp như vậy. Nhưng đó chỉ là sở thích cá nhân của tôi; Tôi thường bắt mình viết kịch bản shell và sau đó viết lại ngay lập tức bằng Perl khi tôi nhận ra rằng tôi đang vượt quá một ngưỡng phức tạp nhất định.
Martin von Wittich

Câu trả lời:


19

Shell với mảng kết hợp

Một số shell hiện đại cung cấp các mảng kết hợp: ksh93, bash 4, zsh. Trong ksh93 và bash, nếu alà một mảng kết hợp, thì đó "${!a[@]}"là mảng các khóa của nó:

for k in "${!a[@]}"; do
  echo "$k -> ${a[$k]}"
done

Trong zsh, cú pháp đó chỉ hoạt động trong chế độ mô phỏng ksh. Nếu không, bạn phải sử dụng cú pháp riêng của zsh:

for k in "${(@k)a}"; do
  echo "$k -> $a[$k]"
done

${(k)a}cũng hoạt động nếu akhông có khóa trống.

Trong zsh, bạn cũng có thể lặp trên cả keys và values ​​cùng một lúc:

for k v ("${(@kv)a}") echo "$k -> $v"

Vỏ không có mảng kết hợp

Việc mô phỏng các mảng kết hợp trong các shell không có chúng là công việc nhiều hơn. Nếu bạn cần mảng kết hợp, có lẽ đã đến lúc đưa vào một công cụ lớn hơn, chẳng hạn như ksh93 hoặc Perl.

Nếu bạn cần các mảng kết hợp trong vỏ POSIX đơn thuần, đây là cách mô phỏng chúng, khi các khóa bị hạn chế chỉ chứa các ký tự 0-9A-Z_a-z(chữ số ASCII, chữ cái và dấu gạch dưới). Theo giả định này, các khóa có thể được sử dụng như một phần của tên biến. Các hàm bên dưới hoạt động trên một mảng được xác định bởi tiền tố đặt tên, thân cây thân mật, không được chứa hai dấu gạch dưới liên tiếp.

## ainit STEM
## Declare an empty associative array named STEM.
ainit () {
  eval "__aa__${1}=' '"
}
## akeys STEM
## List the keys in the associatve array named STEM.
akeys () {
  eval "echo \"\$__aa__${1}\""
}
## aget STEM KEY VAR
## Set VAR to the value of KEY in the associative array named STEM.
## If KEY is not present, unset VAR.
aget () {
  eval "unset $3
        case \$__aa__${1} in
          *\" $2 \"*) $3=\$__aa__${1}__$2;;
        esac"
}
## aset STEM KEY VALUE
## Set KEY to VALUE in the associative array named STEM.
aset () {
  eval "__aa__${1}__${2}=\$3
        case \$__aa__${1} in
          *\" $2 \"*) :;;
          *) __aa__${1}=\"\${__aa__${1}}$2 \";;
        esac"
}
## aunset STEM KEY
## Remove KEY from the associative array named STEM.
aunset () {
  eval "unset __aa__${1}__${2}
        case \$__aa__${1} in
          *\" $2 \"*) __aa__${1}=\"\${__aa__${1}%%* $2 } \${__aa__${1}#* $2 }\";;
        esac"
}

(Cảnh báo, mã chưa được kiểm tra. Phát hiện lỗi đối với các thân và khóa không hợp lệ về mặt cú pháp không được cung cấp.)


5

Tôi không chắc ý của bạn là gì khi lưu trữ, nhưng bạn có thể lặp lại các phím bằng ${!array[@]}cú pháp:

$ typeset -A foo=([key1]=bar [key2]=baz);
$ echo "${!foo[@]}" 
key2 key1

Vì vậy, để lặp lại:

$ for key in "${!foo[@]}"; do echo "$key : ${foo[$key]}"; done
key2 : baz
key1 : bar

Tôi tìm thấy một hướng dẫn ngắn, tốt đẹp về điều này ở đây .


Như đã chỉ ra trong các ý kiến ​​dưới đây, các mảng kết hợp đã được thêm vào trong bashphiên bản 4. Xem tại đây để biết bài viết về tạp chí Linux về chủ đề này.


1
(bash version 4 only)Đó là một điều quan trọng cần lưu ý. Theo truyền thống, bashmảng chỉ là số.
Ricky Beam

1
Bạn có thể muốn sử dụng typesetthay vì declaretrong ví dụ của bạn. Điều đó sẽ làm cho chúng di động giữa bash 4 và ksh93, lần đầu tiên triển khai mảng kết hợp shell.
jlliagre

0

Vỏ không có mảng kết hợp

Không khó lắm khi các phím bị giới hạn [0-9A-Za-z_](số, chữ, gạch dưới).

Thủ thuật thay vì lưu trữ vào mảng [ $ key ], lưu trữ vào các biến Array_ $ key .

Bộ:

eval "array_$key='$value'"

Được:

value=`eval echo '$'array_$key`

Lưu ý: Các giá trị không thể chứa '(trích dẫn đơn).


-1

cái này hoạt động trong bash

cert="first"
web="second"
declare -A assoc_array=(["cert"]="${cert}" ["web"]="${web}")
echo "first is" ${assoc_array[cert]}
echo "second is" ${assoc_array[web]}

HOẶC LÀ

#loop
for i in "${assoc_array[@]}"
do
   echo "$i"
done

Không cần sử dụng afaik


Tôi tin rằng bạn đã bỏ lỡ điểm của câu hỏi.
G-Man nói 'Phục hồi Monica'
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.