Zsh,不使用 eval 的间接数组变量赋值

wok*_*oky 3 zsh array function variable

我有一个变量VARNAME,其中包含另一个变量的名称。我想在不使用 的情况下分配给另一个变量eval。我怎样才能做到这一点?

我不想使用的原因eval如下。首先假设一个用于前置变量的函数foo

% prepend_foo() { foo=("$@" $foo) }
% foo=(1 2)
% print -l $foo
1
2
% prepend_foo x 'a b c' y
% print -l $foo
x
a b c
y
1
2
%
Run Code Online (Sandbox Code Playgroud)

现在考虑一个附加到任何变量的通用函数:

% prepend() { var=$1; shift; eval "$var=($@ ${(P)var})" }
% foo=(1 2)
% print -l $foo
1
2
% prepend foo x 'a b c' y
% print -l $foo
x
a
b
c
y
1
2
%
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,带有空格的变量被分成几个数组项。我无法正确结合报价来实现所需的目标。


在 IRC 上,有人建议使用${name::=word},但这不适用于数组:

21:23 < someone> > b=(bar baz); a=b; : ${(P)a::=(foo ${(P)a})}; typeset -p b
21:23 < machabot> someone: typeset b='(foo bar baz)'
21:23 < someone> dammit that's a string
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 6

要将元素添加到数组中,您可以执行以下操作:

a[1,0]=(more elements)
Run Code Online (Sandbox Code Playgroud)

或者你可以这样做:

a=(more elements "$a[@]")
Run Code Online (Sandbox Code Playgroud)

请注意,执行以下操作:

a=(more elements $a)
Run Code Online (Sandbox Code Playgroud)

将删除 中的空元素$a

现在,要为此创建一个函数,这就是目的eval,但您必须确保语法正确:

prepend() {
  eval "${1}[1,0]"='("${@[2,-1]}")'
}
Run Code Online (Sandbox Code Playgroud)

看看如何将 the("${@[2,-1]}")单引号括起来,以便它按字面意思传递给eval

或者更长的方法,但不起作用prepend var more elements(当变量名称为 时var):

prepend() {
  local var=$1; shift
  eval "$var"='("$@" "${'"$var"'[@]}")'
}
Run Code Online (Sandbox Code Playgroud)

eval您想要评估的代码prepend varname ...是:

 varname=("$@" "${varname[@]")
Run Code Online (Sandbox Code Playgroud)

您不想"$@"在传递到 之前进行扩展eval。只$var需要在那里扩展即可。

请注意,P变量扩展标志与与未经净化的数据一起使用时一样危险eval

var='x[$(uname>&2)0]'
echo "${(P)var}"
Run Code Online (Sandbox Code Playgroud)

将运行该uname命令。