Bash: Why use eval with variable expansion?
I don't understand why I have to use
#!/bin/bash cmd="date --date=\"1 days ago\"" $cmd # Doesn't work eval $cmd # Works
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\""
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:
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:
$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
- Uwe Waldmann - A Guide to Unix Shell Quoting - Common misconceptions
- Bash Command Substitution - LinuxQuestions.org