我有一个变量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
不能是调用函数的本地数组。它只是意味着“可以通过查找函数调用堆栈来找到这个数组”。