Part of the problem with eval is that most of us don't have a clear picture of how it works.
In a nutshell, eval turns a string into a command and executes the command returning the result in place of the command…
$ A=1; B='$A'; echo $B $A $ A=1; B='$A'; eval echo $B 1
Here the single-quotes around ($A) make it a literal instead of a variable so that $B contains ($A) instead of (1). The second pass then executes (echo $A) which yields 1. Using (set -vx), we can see what's happening under the covers…
$ set -vx; A=1; B='$A'; eval echo $B + set -vx + A=1 + B='$A' + eval echo '$A' echo $A ++ echo 1 1
Fire off our "program"…
$ set -vx; A=1; B='$A'; eval echo $B
Show each line and all expansions
+ set -vx
Set variable A to 1
+ A=1
Set variable B to the literal string '$A'
+ B='$A'
Replace B with '$A'
+ eval echo '$A'
Execute
echo $A
Replace (eval echo '$A') with (echo 1) and execute it
++ echo 1
Show the result
1
One problem when trying to write an eval command is to get the quoting right, what is expanded, when etc…It turns out that it's in fact pretty easy when you realize that the result of the first expansion should be bash code just like the one you would put in your script. Let's take an example:
var=value name=var eval echo "$name has a value of \"$\$name\"" #wrong!
To correct this, the trick is simply to replace eval with echo. What echo prints should look just like what you would write in a script.
$ echo echo "$name has a value of \"$\$name\"" echo var has a value of "$$name" #hmm 2 $ and name has not been expanded so too many quotes $ echo echo "$name has a value of \"$$name\"" echo var has a value of "3090name" # $$ is expanded to the pid of the shell $ echo echo "$name has a value of \"\$$name\"" echo var has a value of "$var" # now that looks good. let's replace with eval $ eval echo "$name has a value of \"\$$name\"" var has a value of value #victory
Discussion