First of all we define the meaning of indirect command pointing out that this is not a Unix term but it represents a very common Unix practice. An indirect command is a command given using another command of which the command to execute is either an explicit argument or a shell variable.
The informations given in this section refer to any Unix shell provided that variables are defined according to the shell syntax. Here we want to draw the reader's attention on the many different ways Unix allows to achieve the same operation. It is important that the Unix programmer understands well the several syntax choises when implementing complex scripts and is aware that a mistake can produce very strange or even catastrophic results.
Let us start with a very simple operation, the list of files in the working directory. The same result can be achieved in any of the following ways:
$ type echo eval ls echo is a shell builtin eval is a shell builtin ls is /usr/bin/ls $Then we try echo and ls to see the output produced by the two commands:
$ echo * args bdb cmd.dbs elif excase exists inp loop shodate shodef $ ls args cmd.dbs excase inp shodate bdb elif exists loop shodefBoth commands produce a list of files with slightly different print format. At this point we want to show the different results produced using a shell variable as argument of either echo or eval. We define the local variable jj and apply it both to echo and eval using the same syntax in both cases.
$ jj=ls $ echo jj jj $ echo $jj ls $ echo `$jj` args bdb cmd.dbs elif excase exists inp loop shodate shodef $ #---------------------------------------------------------- $ eval jj jj: not found $ eval $jj args cmd.dbs excase inp shodate bdb elif exists loop shodef $ eval `$jj` ./args: IFS: not found Proc ./args demo for args and shift Full args: bdb cmd.dbs elif excase exists inp loop shodate shodef Type first 3 args bdb cmd.dbs elif Type remaining args 4 and 5 excase exists
In the above example jj is assigned the value of ls. The first echo command lists the word jj, as the variable jj is not prefixed
with $ for variable translation. The second echo command lists the
value of jj. In the third example jj is embedded in backquotes,
therefore echo executes ls as an indirect command and
produces the wanted output.
Then we repeat the same operation using eval. As eval tries to
concatenate and recursively execute commands, at first invocation eval
writes a message as jj is not a command, the second eval acts on
the value of jj that is prefixed by $ and executes ls as an
indirect command, producing the wanted result. The third eval
executes as indirect command args, the first file in the file list
and uses the other file names in the list as arguments of args producing
unwanted and wrong results as shown by the output of the example.
In this example no damage is done as procedure args is a demo of the shift operation and it only prints a selected choice of input arguments, but try to image what might happen if the first file in the list was designed to remove files. Therefore great care must be exercised to avoid serious damages using eval with the wrong arguments.