In bash, dash, ash and sash, this works, but not in zsh:
a=ls
b="-a -l"
$a $b
The simple solution is to correct the code:
a="ls -a -l"
eval "$a"
.. or
a="ls"
b="-a -l"
eval "$a" "$b"
This code works in both bash and zsh.
I got quite a bit more advice today. It hasn’t shown up in the archives yet, but I’ll update this post when it does: http://www.zsh.org/mla/workers/2009/
I’ll copy the content here for posterity.
The simple-but-insecure option would be:
setopt shwordsplit
Stéphane Chazelas gave a thorough answer, including the better and more universal way to do the code:
That behavior of those shells, inherited from the Bourne shell is the cause of half the bugs and especially the security ones in existing shell scripts. It’s been fixed in zsh.
See http://zsh.dotsrc.org/FAQ/zshfaq03.html#l18
Do
$=ato explicitly request the word splitting. The equivalent of the other shells would be
$=~a, that is request both word spitting and filename generation.But chances are that you actually want:
eval $a(
eval "$a"is other shells)if you want the content of
$ato be interpreted as a command line and not as a list of arguments to a simple command.
setopt shwordsplit globsubstenables the Bourne shell behavior. Same with “emulate sh”, if wou’re really keen on shooting yourself in the feet ;)
Note: to get zsh’s behavior in other shells, you’d do:
IFS=; set -fBut that would also disable filename generation everywhere, not only upon variable expansion.
Also note that zsh performs word splitting but not filename generation upon command substitution
$(cmd)or`cmd`(and also the trimming of every trailing character, a bogus behavior of the Bourne shell which it did not fix).Another thing to note (IMO another bug it did not fix) is that
$aexpands to no argument instead of en empty argument when$ais empty just like the other shells, which makes so that even in zsh, it’s generally safer to use quotes anyway just as in the other shells.
I really appreciate that he went out of his way to explain things this thoroughly.
