$ echo $(echo x; echo y)
x y
$ a='echo x; echo y'
$ echo $($a) # expect 'x y'
x; echo y
- Why does command substitution behave in such way?
- How to perform the command substitution for list of commands stored in a variable without using
eval
andbash -c
?
echo $(eval $a)
and echo $(bash -c "$a")
actually does what I want, but I heard that using eval often is a wrong way to solve problems, so I want know how to manage without these commands (using bash -c
is in fact just the same thing)
Best Answer
Word splitting happens quite late in the evaluation of a command. Most crucially for you, it happens after variable expansion and command substitution.
This means that the second line in
will first have
$s
expanded toecho a; echo b
and then have that command executed without splitting it into a compound command consisting of twoecho
s.(details:
$s
gets split into four words,echo
,a;
,echo
andb
. The encapsulating$(...)
executes this as one command,echo
with three arguments,a;
,echo
andb
.)What is given to the outmost
echo
is therefore the stringa; echo b
(actually three words as$(...)
is not in quotes) since this was what was outputted by the innermostecho
.Compare that to
which results in what you'd expect.
Yes, "
eval
is evil", most of the time, andsh -c
is clunky and as fragile. But if you have a bit of shell code that you trust in a string in a shell script, then these tools are the only (?) way to get that code to execute properly since this often requires having to explicitly evaluate the text in the string as shell code (with all phases of the evaluation from start to finish). Especially if it's a compound command.I think it's only due to the Unix shell's intimate relation to text that you're lucky enough to have
echo $($s)
execute something at all.Just think about the steps you'd have to take to get a C program to execute a piece of C code that it gets given as a string...