Softpanorama
(slightly skeptical) Open Source Software Educational Society

May the source be with you, but remember the KISS principle ;-)

Softpanorama Search

Unix eval command

News Books See also Recommended Links

Options

Examples Additional
Examples
Shells Pipes AWK Perl grep find Regex
sort uniq cut tee History Humor Etc

The internal eval command interprets and expands a command line before the shell interprets and expands the line.  Essentially it permits dynamically construct program or statements and then execute them. this is a feature typical for all scripting languages and one of the most powerful one. Among other thing you ca do the following:

The eval command provides an extended feature allowing you to do special command processing. It is used to evaluate variables twice, so you can use the value of one variable as a variable name. The most  popular use of eval is probably processing an input line as a command.  That permits in complex shell scripts using shell constructs in config file (you just read in the config file and then eval it line by line)

Following is the general format of the eval command.

     eval [ command_to_be_interpreted... ]

The shell expands arguments to eval using standard command processing rules. Then the shell forms a space-separated string of all the arguments. The shell reads the string as a command line and processes it again and executes it.

You can use eval to execute a command you read using the read command. For example,

     # read CMD
     cat /etc/group | grep mylogin
     # eval "$CMD"

processes the CMD variable. If you enter any special characters, such as ; or |, eval expands them and the shell reprocesses the results before executing the command line. If you did not use the eval command, the CMD variable would not be interpreted correctly and certain commands would not run. Another example illustrates this concept.

     # CMD='date | wc'
     # $CMD
     usage: date [-a sss.fff] [-u] [tformat] [mmddhhmm[yy]]
     # eval $CMD    

The first line sets CMD to a command containing a pipe. The second command trys to execute the variable CMD. The execution fails because the pipe is not expanded and is passed to date as an argument. Thus date complains about a bad argument. The third line expands CMD to date | wc. The shell executes the line as a proper command.

The following example illustrates how you can use eval to expand variables within a command line to be the name of another variable.

     # eval last='$'{$#}    # expands to last positional parameter
     # X=10
     # Y=X
     # echo '$'$Y
     $X
     # eval echo '$'$Y
     10

Examples

Type the following lines of code; press Return at the end of each line.
     # set One Two Three Four
     # if eval [ ! -f \${$#} ]
     then echo "$4: last argument must be a file!"
        #exit 1
     fi

This code checks for the last argument on the command line to be the name of a file that exists. The first line sets the positional parameters to One Two Three Four. Since Four is not the name of a file, your code will return the message about the last file. The exit is commented out so you are not logged off when the command executes.


Notes:
  • This is a Spartan WHYFF (We Help You For Free) site written by people for whom English is not a native language. Some amount of grammar and spelling errors should be expected.
  • The site contain some broken links as it develops like a living tree... Please try to use Google, Open directory, etc. to find a replacement link (see HOWTO search the WEB for details). We would appreciate if you can mail us a correct link.
Google Search
Open directory

Research Index


Old News ;-)

eval When You Need Another Chance O'Reilly Media by Mike Loukides

 

Sys Admin Miscellaneous Unix Tips Answering Novice Shell Questions

A common eval use is to build a dynamic string containing valid Unix commands and then use eval to execute the string. Why do we need eval? Often, you can build a command that doesn't require eval:
evalstr="myexecutable"
$evalstr   # execute the command string
However, chances are the above command won't work if "myexecutable" requires command-line arguments. That's where eval comes in.

Our man page says that the arguments to the eval command are "read as input to the shell and the resulting commands executed". What does that mean? Think of it as the eval command forcing a second pass so the string's arguments become the arguments of the spawned child shell.

In a previous column, we built a dynamic sed command that skipped 3 header lines, printed 5 lines, and skipped 3 more lines until the end of the file:

evalstr="sed -n '4,\${p;n;p;n;p;n;p;n;p;n;n;n;}' data.file"
eval $evalstr  # execute the command string
This command fails without eval. When the sed command executes in the child shell, eval forces the remainder of the string to become arguments to the child.

Possibly the coolest eval use is building dynamic Unix shell variables. The following stub script dynamically creates shell variables user1 and user2 setting them equal to the strings John and Ed, respectively:

COUNT=1
eval user${COUNT}=John
echo $user1

COUNT=2
eval user${COUNT}=Ed
echo $user2
Pasting Files with paste
Another novice asked how to line up three files line by line sending the output to another file. Given the following:
file1:

1
2
3

file2:

a
b
c

file3:

7
8
9
the output file should look like this:

 

1a7
2b8
3c9
The paste command is a ready-made solution:
paste file1 file2 file3
By default, the delimiter character between the columns is a tab key. The paste command provides a -d delimiter option. Everything after -d is treated as a list. For example, this paste rendition uses the pipe symbol and ampersand characters as a list:
paste -d"|&" file1 file2 file3
The command produces this output:
1|a&7
2|b&8
3|c&9
The pipe symbol character, |, is used between columns 1 and 2, while the ampersand, &, separates column 2 and 3. If the list is completely used, and if the paste command contains more files arguments, then paste starts at the beginning of the list.

To satisfy our original requirement, paste provides a null character, \0, signifying no character. To prevent the shell from interpreting the character, it must also be quoted:

paste -d"\0" file1 file2 file3
Process a String One Character at a Time

Still another user asked how to process a string in a shell script one character at a time. Certainly, advanced scripting languages such as Perl and Ruby can solve this problem, but the cut command's -b option, which specifies the byte position, is a simple alternative:

#!/bin/ksh

mystring="teststring"
length=${#mystring}
count=0

until [ $count -eq $length ]
do
   ((count+=1))
   char=$(echo $mystring|cut -b"$count")
   echo $char
done
In the stub above, string mystring's length is determined using the advanced pattern-matching capabilities of the bash and ksh shells. Any number of external Unix commands can provide a string length, but probably the command with the smallest foot print is expr:
   length=$(expr "$mystring" : '.*')
Also, the bash shell contains a substring expansion parameter:
     ${parameter:offset:length}
According to the bash man page, the substring expansion expands "up to length characters of parameter starting at the character specified offset". Note that the offset starts counting from zero:
#!/bin/bash

mystring="teststring"
length=${#mystring}

ol=1
offset=0

until [ $offset -eq $length ]
do
   echo "${mystring:${offset}:${ol}}"
   ((offset+=1))
done
# end script
Deleting a File Named dash

Finally, a novice inadvertently created a file named with the single character dash, and asked us how to delete the file. No matter how he escaped the dash in the rm command, it still was considered an rm option.

It's easy enough to create the file using the touch command:

 touch -
To remove it, use a path to the file -- either full or relative. Assuming the dash file exists in the mydir directory, provide a full path to the file:
 rm /pathto/mydir/-
Or if the file exists in the current directory, provide a relative path:
 rm ./-
Of course, our old friend find can clobber that file everywhere:
 find . -name "-" |xargs rm

Recommended Links


In case of broken links please try to use Google search. If you find the page please notify us about new location
Google     


 


Copyright © 1996-2009 by Dr. Nikolai Bezroukov. www.softpanorama.org was created as a service to the UN Sustainable Development Networking Programme (SDNP) in the author free time. Submit comments This document is an industrial compilation designed and created exclusively for educational use and is placed under the copyright of the Open Content License(OPL). Site uses AdSense so you need to be aware of Google privacy policy. Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.

Disclaimer:

Last modified: August 08, 2009