Zsh, Indirect array variable assignment without using eval

Clash Royale CLAN TAG#URR8PPP
up vote
2
down vote
favorite
I have a variable VARNAME which contains a name of another variable. I'd like to assign to this another variable without using eval. How can I do that?
Th reason I don't want to use eval is the following. Assume first a function for prepending foo variable:
% 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
%
Now consider a generalized function for appending to any variable:
% 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
%
As you can see, variables with spaces are split into several array items. I couldn't properly combine quote to achieve desired thing.
On IRC, someone suggested using $name::=word, but that doesn't work well with arrays:
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
zsh variable array function
add a comment |Â
up vote
2
down vote
favorite
I have a variable VARNAME which contains a name of another variable. I'd like to assign to this another variable without using eval. How can I do that?
Th reason I don't want to use eval is the following. Assume first a function for prepending foo variable:
% 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
%
Now consider a generalized function for appending to any variable:
% 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
%
As you can see, variables with spaces are split into several array items. I couldn't properly combine quote to achieve desired thing.
On IRC, someone suggested using $name::=word, but that doesn't work well with arrays:
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
zsh variable array function
add a comment |Â
up vote
2
down vote
favorite
up vote
2
down vote
favorite
I have a variable VARNAME which contains a name of another variable. I'd like to assign to this another variable without using eval. How can I do that?
Th reason I don't want to use eval is the following. Assume first a function for prepending foo variable:
% 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
%
Now consider a generalized function for appending to any variable:
% 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
%
As you can see, variables with spaces are split into several array items. I couldn't properly combine quote to achieve desired thing.
On IRC, someone suggested using $name::=word, but that doesn't work well with arrays:
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
zsh variable array function
I have a variable VARNAME which contains a name of another variable. I'd like to assign to this another variable without using eval. How can I do that?
Th reason I don't want to use eval is the following. Assume first a function for prepending foo variable:
% 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
%
Now consider a generalized function for appending to any variable:
% 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
%
As you can see, variables with spaces are split into several array items. I couldn't properly combine quote to achieve desired thing.
On IRC, someone suggested using $name::=word, but that doesn't work well with arrays:
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
zsh variable array function
asked May 18 at 19:39
woky
22216
22216
add a comment |Â
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
3
down vote
To prepend elements to an array, you can just do:
a[1,0]=(more elements)
Or you can do:
a=(more elements "$a[@]")
Note that doing:
a=(more elements $a)
would remove the empty elements in $a.
Now, to make a function for that, that's what eval is for, but you have to get the syntax right:
prepend()
eval "$1[1,0]"='("$@[2,-1]")'
See how the ("$@[2,-1]") is single-quoted so it is passed literally to eval.
Or the longer way, but wouldn't work for prepend var more elements (when the variable name is var):
prepend()
local var=$1; shift
eval "$var"='("$@" "$'"$var"'[@]")'
The code you want to eval evaluate upon prepend varname ... is:
varname=("$@" "${varname[@]")
You don't want "$@" to be expanded before being passed to eval. Only $var needs to be expanded there.
Note that the P variable expansion flag is as dangerous as eval when used with unsanitized data.
var='x[$(uname>&2)0]'
echo "$(P)var"
Will run that uname command.
add a comment |Â
up vote
0
down vote
Your prepend function can be written without eval, if you loop over the elements to unshift them one at a time.
$ 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
$
Note that -g is needed for typeset to accept setting a non-local array element, but doesn't mean that the array referenced by $1 can't be local to the calling function. It just means "it's OK to look up the function call stack to find this array".
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
3
down vote
To prepend elements to an array, you can just do:
a[1,0]=(more elements)
Or you can do:
a=(more elements "$a[@]")
Note that doing:
a=(more elements $a)
would remove the empty elements in $a.
Now, to make a function for that, that's what eval is for, but you have to get the syntax right:
prepend()
eval "$1[1,0]"='("$@[2,-1]")'
See how the ("$@[2,-1]") is single-quoted so it is passed literally to eval.
Or the longer way, but wouldn't work for prepend var more elements (when the variable name is var):
prepend()
local var=$1; shift
eval "$var"='("$@" "$'"$var"'[@]")'
The code you want to eval evaluate upon prepend varname ... is:
varname=("$@" "${varname[@]")
You don't want "$@" to be expanded before being passed to eval. Only $var needs to be expanded there.
Note that the P variable expansion flag is as dangerous as eval when used with unsanitized data.
var='x[$(uname>&2)0]'
echo "$(P)var"
Will run that uname command.
add a comment |Â
up vote
3
down vote
To prepend elements to an array, you can just do:
a[1,0]=(more elements)
Or you can do:
a=(more elements "$a[@]")
Note that doing:
a=(more elements $a)
would remove the empty elements in $a.
Now, to make a function for that, that's what eval is for, but you have to get the syntax right:
prepend()
eval "$1[1,0]"='("$@[2,-1]")'
See how the ("$@[2,-1]") is single-quoted so it is passed literally to eval.
Or the longer way, but wouldn't work for prepend var more elements (when the variable name is var):
prepend()
local var=$1; shift
eval "$var"='("$@" "$'"$var"'[@]")'
The code you want to eval evaluate upon prepend varname ... is:
varname=("$@" "${varname[@]")
You don't want "$@" to be expanded before being passed to eval. Only $var needs to be expanded there.
Note that the P variable expansion flag is as dangerous as eval when used with unsanitized data.
var='x[$(uname>&2)0]'
echo "$(P)var"
Will run that uname command.
add a comment |Â
up vote
3
down vote
up vote
3
down vote
To prepend elements to an array, you can just do:
a[1,0]=(more elements)
Or you can do:
a=(more elements "$a[@]")
Note that doing:
a=(more elements $a)
would remove the empty elements in $a.
Now, to make a function for that, that's what eval is for, but you have to get the syntax right:
prepend()
eval "$1[1,0]"='("$@[2,-1]")'
See how the ("$@[2,-1]") is single-quoted so it is passed literally to eval.
Or the longer way, but wouldn't work for prepend var more elements (when the variable name is var):
prepend()
local var=$1; shift
eval "$var"='("$@" "$'"$var"'[@]")'
The code you want to eval evaluate upon prepend varname ... is:
varname=("$@" "${varname[@]")
You don't want "$@" to be expanded before being passed to eval. Only $var needs to be expanded there.
Note that the P variable expansion flag is as dangerous as eval when used with unsanitized data.
var='x[$(uname>&2)0]'
echo "$(P)var"
Will run that uname command.
To prepend elements to an array, you can just do:
a[1,0]=(more elements)
Or you can do:
a=(more elements "$a[@]")
Note that doing:
a=(more elements $a)
would remove the empty elements in $a.
Now, to make a function for that, that's what eval is for, but you have to get the syntax right:
prepend()
eval "$1[1,0]"='("$@[2,-1]")'
See how the ("$@[2,-1]") is single-quoted so it is passed literally to eval.
Or the longer way, but wouldn't work for prepend var more elements (when the variable name is var):
prepend()
local var=$1; shift
eval "$var"='("$@" "$'"$var"'[@]")'
The code you want to eval evaluate upon prepend varname ... is:
varname=("$@" "${varname[@]")
You don't want "$@" to be expanded before being passed to eval. Only $var needs to be expanded there.
Note that the P variable expansion flag is as dangerous as eval when used with unsanitized data.
var='x[$(uname>&2)0]'
echo "$(P)var"
Will run that uname command.
edited May 18 at 20:40
answered May 18 at 20:32
Stéphane Chazelas
279k53513845
279k53513845
add a comment |Â
add a comment |Â
up vote
0
down vote
Your prepend function can be written without eval, if you loop over the elements to unshift them one at a time.
$ 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
$
Note that -g is needed for typeset to accept setting a non-local array element, but doesn't mean that the array referenced by $1 can't be local to the calling function. It just means "it's OK to look up the function call stack to find this array".
add a comment |Â
up vote
0
down vote
Your prepend function can be written without eval, if you loop over the elements to unshift them one at a time.
$ 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
$
Note that -g is needed for typeset to accept setting a non-local array element, but doesn't mean that the array referenced by $1 can't be local to the calling function. It just means "it's OK to look up the function call stack to find this array".
add a comment |Â
up vote
0
down vote
up vote
0
down vote
Your prepend function can be written without eval, if you loop over the elements to unshift them one at a time.
$ 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
$
Note that -g is needed for typeset to accept setting a non-local array element, but doesn't mean that the array referenced by $1 can't be local to the calling function. It just means "it's OK to look up the function call stack to find this array".
Your prepend function can be written without eval, if you loop over the elements to unshift them one at a time.
$ 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
$
Note that -g is needed for typeset to accept setting a non-local array element, but doesn't mean that the array referenced by $1 can't be local to the calling function. It just means "it's OK to look up the function call stack to find this array".
answered Jun 29 at 0:02
Tim Smith
1414
1414
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f444690%2fzsh-indirect-array-variable-assignment-without-using-eval%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password