我这样设置关联数组:
$ 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"
如何用变量替换数组内容?
答案1
set -A array value1 value2
是 80 年代早期用于定义普通数组的古老 ksh 语法。它不定义关联数组,仅支持与 ksh88 兼容。
k
和参数扩展标志v
仅对关联数组的变量有意义。对于其他类型的变量(包括普通数组),它们将被简单地忽略。所以这里,与or"${(@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[@]"
1 David Korn 选择了这个选项-A
,因为set -a
Bourne shell 已经被占用了。还解释了为什么read -A
在 ksh93 或 zsh 中使用它来将一行读入数组。bash
不支持,set -A
尽管它的数组设计基于 ksh88(虽然zsh
数组设计更接近 csh 而不是 ksh),并且选择read -a
而不是read -A
.一个可能造成混淆的来源是typeset -a
声明一个普通数组,而typeset -A
声明一个关联数组(均来自 ksh)
² 并依次将和for k v
分配给数组的元素,这解释了输出以及为什么它的顺序与分配中的顺序相同(而对于关联数组,不能保证顺序)。k
v
³ 该语法实际上是从zsh 于 1990 年出现,后来进入 ksh93(尽管在那里,作为大型变量类型的一部分,还包括复合变量)和 bash(直到 1996 年 2.0 才出现数组),尽管它很大程度上受到 csh 的启发(第一个带有 70 年代末数组的 shell),语法是set array = (foo bar)