ZSH:如何动态设置关联数组名称和内容?

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"如何用变量替换数组内容?

答案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 -aBourne shell 已经被占用了。还解释了为什么read -A在 ksh93 或 zsh 中使用它来将一行读入数组。bash不支持,set -A尽管它的数组设计基于 ksh88(虽然zsh数组设计更接近 csh 而不是 ksh),并且选择read -a而不是read -A.一个可能造成混淆的来源是typeset -a声明一个普通数组,而typeset -A声明一个关联数组(均来自 ksh)

² 并依次将和for k v分配给数组的元素,这解释了输出以及为什么它的顺序与分配中的顺序相同(而对于关联数组,不能保证顺序)。kv

³ 该语法实际上是zsh 于 1990 年出现,后来进入 ksh93(尽管在那里,作为大型变量类型的一部分,还包括复合变量)和 bash(直到 1996 年 2.0 才出现数组),尽管它很大程度上受到 csh 的启发(第一个带有 70 年代末数组的 shell),语法是set array = (foo bar)

相关内容