Bash: Why use eval with variable expansion?
Contents
Problem
I don't understand why I have to use eval
:
#!/bin/bash cmd="date --date=\"1 days ago\"" $cmd # Doesn't work eval $cmd # Works
Solution
Before the shell executes a command, it performs the following operations (check the manual for details):
- Syntax analysis (Parsing)
- Brace expansion
- Tilde expansion
- Parameter and variable expansion
- Command substitution
- Arithmetic expansion
- Word splitting
- Filename expansion
- Quote removal
It is important to realize that parsing takes place before parameter and command substitution. The result of a step n
is subject to the next steps (n+
), but the preceding steps (n-
) are not re-executed. In other words: after for example variable expansion (step 4) the result is not re-parsed (step 1).
In the example of the command:
$cmd # cmd="date --date=\"1 days ago\""
the command date --date=\"1 days ago\"
is the result of variable expansion (step 4). Quote removal (step 9) removes the backslashes and turns the command into date --date="1 days ago"
. But since parsing (step 1) already has taken place, "1 days ago" is not seen as 1 argument but as 3 separate arguments: "1
, days
and ago"
, which gives you the error message:
date: extra operand `ago"' Try `date --help' for more information.
To force one more run through the parsing/expansion procedure, use:
eval $cmd
Now first $cmd
is expanded (steps 1-9) to date --date="1 days ago"
. Then eval
causes the expanded string to be re-parsed again (steps 1-9), resulting in the correct command:
date --date="1 days ago" Wed Nov 29 08:11:46 CET 2006
See also
- http://www.mpi-sb.mpg.de/~uwe/lehre/unixffb/quoting-guide.html#para:sh-misconceptions
- Uwe Waldmann - A Guide to Unix Shell Quoting - Common misconceptions
- http://www.linuxquestions.org/questions/showthread.php?p=2523172#post2523172
- Bash Command Substitution - LinuxQuestions.org