How to separate multiple commands passed to eval in bash

You are passing the newline into eval. So it's like you are on the console typing this:

el@voyager$ echo a\necho b
anecho b

So the first echo is understood correctly, and it thinks you want quotes around the rest. The backslash seems to be ignored. Perhaps you meant something like this:

el@voyager$ echo -e 'a\n'; echo b
a

b

Option 1:

delimit statements passed into eval with a semicolon like this:

x='echo a'
y='echo b'
z="$x;$y"
eval $x
eval $y
eval $z

prints:

a
b
a
b

Option 2:

Put the newline in the place where it will be interpreted by the echo, like this:

x='echo -e "a\n"'
y='echo b'
z="$x;$y"
eval $x
eval $y
eval $z

prints:

a

b
a

b

Now the newline is preserved and interpreted by the echo, not the eval.


\n is not a newline; it's an escape sequence that in some situations will be translated into a newline, but you haven't used it in one of those situations. The variable $z doesn't wind up containing a newline, just backslash followed by "n". As a result, this is what's actually being executed:

$ echo a\necho b
anecho b

You can either use a semicolon instead (which requires no translation), or use \n in a context where it will be translated into a newline:

$ newline=$'\n'
$ x='echo a'
$ y='echo b'
$ z="$x$newline$y"
$ eval "$z"
a
b

Note the double-quotes around "$z" -- they're actually critical here. Without them, bash will word-split the value of $z, turning all whitespace (spaces, tabs, newlines) into word breaks. If that happens, eval will receive the words "echo" "a" "echo" b", effectively turning the newline into a space:

$ eval $z
a echo b

This is yet another in the long list of cases where it's important to double-quote variable references.

Tags:

Shell

Bash

Eval