The most important difference between
bash -c "$1"
And
eval "$1"
Is that the former runs in a subshell and the latter does not. So:
set -- 'var=something' bash -c "$1" echo "$var"
OUTPUT:
#there doesn't seem to be anything here
set -- 'var=something' eval "$1" echo "$var"
OUTPUT:
something
I have no idea why anyone would ever use the executable bash
in that way, though. If you must invoke it, use the POSIX guaranteed built-in sh
. Or (subshell eval)
if you wish to protect your environment.
Personally, I prefer the shell's .dot
above all.
printf 'var=something%d ; echo "$var"\n' `seq 1 5` | . /dev/fd/0
OUTPUT
something1 something2 something3 something4 something5
BUT DO YOU NEED IT AT ALL?
The only cause to use either, really, is in the event that your variable actually assigns or evaluates another, or word-splitting is important to the output.
For instance:
var='echo this is var' ; $var
OUTPUT:
this is var
That works, but only because echo
doesn't care about its argument count.
var='echo "this is var"' ; $var
OUTPUT:
"this is var"
See? The double-quotes come along because the result of the shell's expansion of $var
is not evaluated for quote-removal
.
var='printf %s\\n "this is var"' ; $var
OUTPUT:
"this is var"
But with eval
or sh
:
var='echo "this is var"' ; eval "$var" ; sh -c "$var"
OUTPUT:
this is var this is var
When we use eval
or sh
the shell takes a second pass at the results of the expansions and evaluates them as a potential command as well, and so the quotes make a difference. You can also do:
. <<VAR /dev/fd/0 ${var:=echo "this is var"} #END VAR
OUTPUT
this is var
e='echo foo'; $e
works just fine.