ZSH:如何動態設置關聯數組名稱和內容?
我這樣設置我的關聯數組:
$ 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 兼容。和參數擴展標誌僅對關聯數組
k
的v
變數有意義。對於其他類型的變數,包括普通數組,它們會被簡單地忽略。所以在這裡,與或"${(@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 中選擇
-A
的set -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)