If I run this:
echo "echo 'a'; echo 'b'"
It produces a string which I can then run, and it works – echoes a\nb\n
.
However, this does not work:
$(echo "echo 'a'; echo 'b'")
Why not? It doesn't work for any command, not just echo. How do I execute a string containing two or more commands?
Best Answer
In
$(echo "echo 'a'; echo 'b'")
, the shell sees a command substitution. And that's it. So that's going to be a simple command whose arguments are the resulting of the split+glob operator upon the expansion of the command substitution.The shell will take the output of the
echo "echo 'a'; echo 'b'"
command, in this caseecho 'a'; echo 'b'\n
, remove the trailing newline characters so that becomesecho 'a'; echo 'b'
, split that according the value of the$IFS
variable.If
$IFS
has not been changed from its default, that will be 4 words:echo
,'a';
,echo
and'b'
. Each of those words will be subject to globbing. Here, none contain globbing characters, so those words will stay as they are.So we've got 4 arguments to run a simple command. The first argument will be used to derive the command to run.
echo
is built-in most shells. So the shell will call itsecho
builtin with those 4 arguments.echo
ignores its first (0th) argument and outputs the other ones separated by space characters and terminated by a newline character. Someecho
implementations expand backslash escape sequences, but there's none here. Soecho
will output:If you want to eval it, that is if you want to have that string interpreted as shell code, use
eval
:That's also recognised as a simple command. Because of the quotes, the shell sees two "words":
eval
andecho 'a'; echo 'b'
. Again, those will make up the arguments to the command that is derived from the first.Here the command is the shell's
eval
builtin command. Again,eval
ignores its first agument. What it does is concatenate its other arguments (here there's only one) with spaces and interpret the resulting string as shell code. When interpretingThe shell sees an unquoted
;
which delimits commands. The first one is treated as a simple command which ends up callingecho
with two arguments... etc.