Classic Shell Scripting - Arnold Robbins [100]
The eval command exists to supersede the normal command-line substitution and evaluation order, making it possible for a shell script to build up commands dynamically. This is a powerful facility, but it must be used carefully. Because the shell does so many different kinds of substitutions, it pays to understand the order in which the shell evaluates input lines.
Subshells and code blocks give you two choices for grouping commands. They have different semantics, so you should use them appropriately.
Built-in commands exist either because they change the shell's internal state and must be built-in (such as cd), or for efficiency (such as test). The command search order that allows functions to be found before regular built-ins, combined with the command command, make it possible to write shell functions that override built-in commands. This has its uses. Of the built-in commands, the set command is the most complicated.
Chapter 8. Production Scripts
In this chapter, we move on to some more-complex processing tasks. The examples that we consider are each of general utility, yet they are completely different from one another, and are absent from most Unix toolboxes.
The programs in this chapter include examples of command-line argument parsing, computing on remote hosts, environment variables, job logging, parallel processing, runtime statement evaluation with eval, scratch files, shell functions, user-defined initialization files, and consideration of security issues. The programs exercise most of the important statements in the shell language, and give a flavor of how typical Unix shell scripts are written. We developed them for this book, and they have proved to be solid production tools that we use, and rely on, in our daily work.
Path Searching
Some programs support searching for input files on directory paths, much like the Unix shell searches the colon-separated directory list in PATH for executable programs. This makes it easier for users, who can refer to files by shorter names and need not be aware of exactly where in the filesystem they are found. Unix doesn't provide any special commands or system calls for finding a file in a search path, even though there is historical precedent in other operating systems for such support. Fortunately, it isn't hard to implement a path search, given the right tools.
Rather than implement a path search for one particular program, let's write a new tool that takes as arguments an environment variable name whose expansion is the desired search path, followed by zero or more file patterns, and have it report the locations of matching files. Our program will then be of general utility in all other software that needs path-search support. (This is an example of the "Detour to build specialized tools" principle that we mentioned in Chapter 1.)
It is sometimes useful to know whether a file is found more than once in the path because you might want to adjust the path to control which version is found, when differing versions exist in the path. Our program should offer the user a command-line option to choose between reporting just the first one found, and reporting all of them. Also, it is becoming standard practice for software to provide an identifying version number on request, and to offer brief help so that the user often need not reread the program's manual pages to get a reminder about an option name. Our program provides those features too.
The complete program is shown later in Example 8-1, but because of its length, we present it here first as a semiliterate program, a sequence of fragments of descriptive prose and shell code.
We begin with the usual introductory comment block. It starts with the magic line that identifies the program, /bin/sh, to be used to execute the script. The comment block then continues with a brief statement of what the program does, and how it is used:
#! /bin/sh -
#
# Search for one or more ordinary files or file patterns on a search
# path defined by a specified environment variable.
#
# The output on standard output