|
Softpanorama
(slightly skeptical)
Open Source Software Educational Society |
May the
source be with you,
but remember the KISS principle ;-)
|
Unix eval command
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:
- Execute a command line you read using the read command.
- Find the value of a variable whose name is derived from the value
of another variable.
- To repeat a stage or portion of command processing.
- To apply results of expansions to earlier stages of the expansion.
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.
|
|
|
|
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
In case of broken links
please try to use Google search. If you find the page please notify
us about new location
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:
- The statements, views and opinions presented on
this web page are those of the author and are not endorsed by, nor do they necessarily
reflect, the opinions of the author present and former employers, SDNP or any other
organization the author may be associated with.
- We do not warrant the correctness of the information provided or its
fitness for any purpose
- In no way this site is associated with or endorse cybersquatters
using
the term "softpanorama" with other main or country domains (e.g. softpanorama.com) with
bad faith intent to profit from the goodwill belonging to
someone else.
Last modified:
August 08, 2009