If you read the previous article (Section 27.7), you saw that, most of the time, the shell evaluates the command line "in the right order." But what about when it doesn't? Here's a situation that the shell can't handle. It's admittedly contrived, but it's not too different from what you might find in a shell program (Section 1.8):
% set b=\$a % set a=foo % echo $b $a
When we use the variable $b, we'd like to get the variable $a, read it, and use its value. But that doesn't happen. Variable substitution happens once, and it isn't recursive. The value of $b is $a, and that's it. You don't go any further.
But there's a loophole. The eval command says, in essence, "Give me another chance. Re-evaluate this line and execute it." Here's what happens if we stick eval before the echo:
% eval echo $b foo
The shell converts $b into $a; then eval runs through the command-line evaluation process again, converting echo $a into echo foo -- which is what we wanted in the first place!
Here's a more realistic example; you see code like this fairly often in Bourne shell scripts:
... command='grep $grepopts $searchstring $file' for opt do case "$opt" in file) output=' > $ofile' ;; read) output=' | more' ;; sort) postproc=' | sort $sortopts';; esac done ... eval $command $postproc $output
Do you see what's happening? We're constructing a command that will look something like:
grep $grepopts $searchstring $file | sort $sortopts > $ofile
But the entire command is "hidden" in shell variables, including the I/O redirectors and various options. If the eval isn't there, this command will blow up in all sorts of bizarre ways. You'll see messages like | not found, because variable expansion occurs after output redirection. The "nested" variables (like $ofile, which is used inside $output) won't be expanded either, so you'll also see $ofile not found. Putting an eval in front of the command forces the shell to process the line again, guaranteeing that the variables will be expanded properly and that I/O redirection will take place.
eval is incredibly useful if you have shell variables that include other shell variables, aliases, I/O redirectors, or all sorts of perversities. It's commonly used within shell scripts to "evaluate" commands that are built during execution. There are more examples of eval in Section 5.3 and others.
-- ML
Copyright © 2003 O'Reilly & Associates. All rights reserved.