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

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

我有一个变量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
%

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

% 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
%

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


在 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

答案1

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

a[1,0]=(more elements)

或者你可以这样做:

a=(more elements "$a[@]")

请注意,执行以下操作:

a=(more elements $a)

将删除 中的空元素$a

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

prepend() {
  eval "${1}[1,0]"='("${@[2,-1]}")'
}

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

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

prepend() {
  local var=$1; shift
  eval "$var"='("$@" "${'"$var"'[@]}")'
}

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

 varname=("$@" "${varname[@]")

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

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

var='x[$(uname>&2)0]'
echo "${(P)var}"

将运行该uname命令。

答案2

如果您循环遍历元素以一次取消移动一个元素,则您的prepend函数可以在没有 的情况下编写。eval

$ prepend () {
then> local i=$#*
then> while [[ $i > 1 ]]; do
then>   typeset -g "${1}[1,0]=$*[$i]"
then>   i=$((i - 1))
then> done
then> }
$ foo=(a 'b c' d)
$ prepend foo m 'n o p' q r
$ print -l $foo
m
n o p
q
r
a
b c
d
$ 

请注意,-g排版需要接受设置非本地数组元素,但这并不意味着 引用的数组$1不能是调用函数的本地数组。它只是意味着“可以通过查找函数调用堆栈来找到这个数组”。

相关内容