There are probably a lot of Linux users who have never encountered the eval command. In fact, it’s not really a “command”, but a bash built-in. If you ask “which eval”, bash is going to pretend it simply can’t find it, but if you type “eval date”, it will show you the current date and time in just the same way it would if you typed “date” by itself. Of course, this isn’t how you should be using eval since this example adds nothing to the output and requires you to type two words instead of one.
What eval was designed to do is quite different than running a command that doesn’t need any help. It’s meant to process the value of a variable as a command. For example, if you set up a variable that includes the command to display the current time in Sydney, Australia, it would probably look like this:
$ dt="TZ='Australia/Sydney' date"
You could then run it like this:
$ eval $dt Thu Jul 7 06:32:14 AM AEST 2022
Doing that can save you the trouble of memorizing the date command syntax and specifying a time zone, but let’s look a little more closely at eval to see what else it can do for you.
The bash man page will tell you a little about the eval command, though you would have to scroll down nearly 5,000 lines to find it. There are, after all, no man pages for built-ins. Here’s what it would tell you:
The args are read and concatenated together into a single com- mand. This command is then read and executed by the shell, and its exit status is returned as the value of eval. If there are no args, or only null arguments, eval returns 0.
Of course, for anything you do by typing commands in the terminal window, eval isn’t likely to save you much time or effort. You could, after all, create an alias to do the same work for you. Here’s how that would look:
$ alias dt="TZ='Australia/Sydney' date" $ dt Thu Jul 7 06:37:31 AM AEST 2022
Save that alias in your .bashrc file and you’ll have an easy time checking what time it is in Sydney whenever you feel the urge.
When you’re building a complex command in pieces, however, especially in scripts which need to collect the needed data when they are run, using the eval command to run the command can make running the command a lot easier.
As an example, while working on a recent script, I needed to find words that were five letters long, had specific letters in known positions and other specific letters in uncertain positions. I also knew that a number of letters were not included in the words that I needed to find. Step-by-step, the script built a long string of grep commands to look through the words file to find only the words that fit my specifications. Here’s an example of what such a command might look like with all of its grep (match) and its grep -v (ignore) commands and the match that it found:
$ grep ^ch..t$ /usr/share/dict/words | eval grep -v 'q' | grep -v 'w' | grep -v 'r' | grep -v 'y' | grep -v 'u' | grep -v 'i' | grep -v 'o' | grep -v 'p' | grep -v 's' | grep -v 'd' | grep -v 'f' | grep -v 'g' | grep -v 'j' | grep -v 'k' | grep -v 'l' | grep -v 'z' | grep -v 'x' | grep -v 'v' | grep -v 'b' | grep -v 'n' | grep -v 'm' | grep a | grep e | grep -v ..a.. | grep -v ...e. cheat
In fact, if you run that command against your words file, you should get the same response. If you turn it into a variable as shown below, it will work the same.
$ cmd="grep ^ch..t$ /usr/share/dict/words | grep -v 'q' | grep -v 'w' | grep -v 'r' | grep -v 'y' | grep -v 'u' | grep -v 'i' | grep -v 'o' | grep -v 'p' | grep -v 's' | grep -v 'd' | grep -v 'f' | grep -v 'g' | grep -v 'j' | grep -v 'k' | grep -v 'l' | grep -v 'z' | grep -v 'x' | grep -v 'v' | grep -v 'b' | grep -v 'n' | grep -v 'm' | grep a | grep e | grep -v ..a.. | grep -v ...e." $ eval $cmd cheat
My script uses eval to run the $cmd variable as a command and passes the output to the column command which makes the output more useful when there are dozens or hundreds of matching words. The result in the example shown was the single word “cheat” pulled from the nearly half a million lines in the words file. All I needed to do was answer a few questions about what I knew and didn’t know.
eval $cmd | column
Wrap-Up
The eval command can be used to run simple or very complex commands that are saved as variables. It evaluates the commands and arguments in the variable and then executes them. It’s most useful when you are constructing long and complicated commands – especially in scripts when the details depend on data that changes or responses provided when the scripts are run.
Copyright © 2022 IDG Communications, Inc.