Zsh

ZSH:如何動態設置關聯數組名稱和內容?

  • May 13, 2022

我這樣設置我的關聯數組:

$ foo=test
$ set -A $foo "a b" "1 2" "c d" "3 4"
$ for key val in "${(@kv)test}"; do echo "$key -> $val" done
a b -> 1 2
c d -> 3 4

如何用"a b" "1 2" "c d" "3 4"變數替換數組內容?

set -A array value1 value2是 80 年代早期用於定義普通數組的古老 ksh 語法。它沒有定義關聯數組,僅支持與 ksh88 兼容。

和參數擴展標誌僅對關聯數組kv變數有意義。對於其他類型的變數,包括普通數組,它們會被簡單地忽略。所以在這裡,與或"${(@kv)test}"相同,並擴展到普通數組²的所有元素。"${(@)test}"``"$test[@]"

要聲明關聯數組,您寧願使用現代

assoc=(
 'key 1' 'value 1'
 'key 2' 'value 2'
)

聲明assoc為關聯數組後的語法³ :

typeset -A assoc

在最近的版本中,現在它typeset已成為雙重關鍵字/內置,您還可以同時進行聲明和賦值:

typeset -A assoc=(
 'key 1' 'value 1'
 'key 2' 'value 2'
)

然後你可以這樣做:

printf '"%s" => "%s"\n' "${(@kv)assoc}"

或者

for k v ("${(@kv)assoc}") print -r -- "$k => $v"

或者:

for k ("${(@k)assoc}") print -r -- "$k => $assoc[$k]"

循環遍歷它的鍵和值。

要定義一個關聯數組,其名稱儲存在鍵和值列表中的變數中,您可以使用:

setassoc() {
 typeset -gA $1; shift
 eval "$1"='( "$@[2,-1]" )'
}
foo=test
setassoc $foo 'key 1' 'value 1' 'key 2' 'value 2'

或者,如果鍵和值列表儲存在普通數組變數中:

array=('key 1' 'value 1' 'key 2' 'value 2')
setassoc $foo "$array[@]"

順便說一句set -A,可以在這裡使用來避免eval(並不是說在這裡使用這種方式有什麼問題eval),但是您需要首先確保將變數設置為關聯數組:

foo=test
typeset -A $foo
set -A $foo "$array[@]"

請注意,如果啟用了 ksh 仿真(具體來說,如果ksharrays啟用了該選項),則需要將其更改為:

set -A $foo -- "$array[@]"

¹ David Korn 從 Bourne shell 中選擇-Aset -a已被使用。還解釋了為什麼read -A在 ksh93 或 zsh 中使用將一行讀入數組。即使它的數組設計基於 ksh88 的數組設計bash也不支持(而數組設計更接近 csh 而不是 ksh),並選擇了. 一個可能的混淆來源是聲明一個普通數組,而用於關聯數組(都來自 ksh)set -A``zsh``read -a``read -A``typeset -a``typeset -A

² 並依次for k v分配k和分配v給數組的元素,這解釋了輸出以及為什麼它與分配中的順序相同(而對於關聯數組,不能保證順序)。

³ 該語法實際上來自1990 年的 zsh,後來進入了 ksh93(儘管在那裡,作為還包括複合變數的大型變數類型的一部分)和 bash(直到 1996 年的 2.0 才有數組),儘管它是很大程度上受到 csh(70 年代後期第一個帶有數組的 shell)的啟發,其中語法是set array = (foo bar)

引用自:https://unix.stackexchange.com/questions/702295