Tải bản đầy đủ (.pdf) (11 trang)

Accepting Command-Line Options, Switches, and Parameters

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (96.9 KB, 11 trang )

31
■ ■ ■
CHAPTER 5
Accepting Command-Line
Options, Switches, and
Parameters
S
ometimes you may want to pass optional parameters to your script, allowing its behav-
ior to be controlled more precisely. For example, the tar archiving utility uses optional
parameters. It creates archives and restores directory and file trees, but it can do so in dif-
ferent ways. The GNU version of tar has roughly 80 different options that can be used in
various combinations to tailor the ways in which the utility performs. The major benefit of
this technique is that you can write a single program and have it perform multiple tasks
based on the command-line input. Additionally, you’re not duplicating code by writing
smaller, more specific scripts tailored to each individual task.
You are unlikely to use the code demonstrated here in its current form, as it is designed
to demonstrate processing of command-line options within a framework of a specific task
for a specific application environment. However, it’s a good basic set of simple utilities
that you could give to first-level support staff for basic initial troubleshooting so they
don’t have to remember all the paths and commands. That could be especially helpful if
that support staff is not very proficient with the command line. To modify the sample
code for more general use, you could have the code view the /var/log/messages file with
one switch, perform a df -k with another switch, and perform a netstat -a with yet
another. This is much like creating a set of command-line aliases to save time by reducing
keystrokes for commonly used commands and utilities.
Most of the scripts I have written don’t use many options because they are fairly spe-
cific in their purpose. If you need a single option, you can easily have the user supply it
as a command-line parameter and check the value of $1 to see if an option was in fact
passed to the script. The complexity of this technique increases dramatically when you
have multiple options that can be used in combination independently of each other,
and the method of evaluating command-line parameters becomes unwieldy. Also con-


sider the difficulty of accounting for users’ foibles and the ways users may specify the
options—sometimes erroneously.
32
CHAPTER 5

ACCEPTING COMMAND-LINE OPTIONS, SWITCHES, AND PARAMETERS
For instance, a typical tar command might be tar -xvf file.tar. This could also be
entered as tar -x -v -f file.tar. Attempting to account for all possible combinations of
user-specified options using shell-script code that works with positional variables would
be very problematic.
This brings us to the getopts utility, which handles command-line switches much
more elegantly. You have to concern yourself only with how the script will function based
on the supplied parameters, not how to read the parameters and account for their poten-
tial variability.
The following example code does not represent a full script. It is a single function that
would get sourced into your environment through a login script such as /etc/profile or
through a standard library of functions (see Chapter 2). To use this function, you type its
name (jkl) at the command line and pass it various parameters to perform specific tasks.
The code was used in an environment where there were multiple machines, each of
which had one or more versions of the same set of applications installed. Troubleshooting
problems with the active application became tedious and time-consuming because you
had to begin by determining which installed version was active. The one constant was a
single configuration file residing in a known location that held the active version of the
installed software. The following code allows users to immediately switch to the correct
configuration or log directory for quick troubleshooting:
APPHOME=/usr/local/apphome
if [ ! -f $APPHOME/myapp.sh ]
then
echo "Myapp is not installed on this system so jkl is not functional"
return 1

fi
First you define a variable containing the top of the directory subtree where the
installed applications live; then you determine if the main configuration file exists. If it
does not exist, the script should exit and provide a notification. Next comes the jkl()
function itself.
jkl () {
Usage="Usage: \n \
\tjkl [-lbmcdxh] [-f filename]\n \
\t\t[-h] \tThis usage text.\n \
\t\t[-f filename] \t cat the specified file. \n \
\t\t[-l] \tGo to application log directory with ls. \n \
\t\t[-b] \tGo to application bin directory. \n \
\t\t[-c] \tGo to application config directory.\n \
\t\t[-m] \tGo to application log directory and more log file.\n \
\t\t[-d] \tTurn on debug information.\n \
\t\t[-x] \tTurn off debug information.\n"
APPLOG=myapp_log
UNAME=`uname -n`
CHAPTER 5

ACCEPTING COMMAND-LINE OPTIONS, SWITCHES, AND PARAMETERS
33
DATE=`date '+%y%m'`
MYAPP_ID=$APPHOME/myapp.sh
The start of the function sets up a number of variables, the most interesting of which
is Usage. The Usage variable is being formatted manually for the output of the usage
statement with tabs and carriage returns. For more information on these character com-
binations and definitions, consult the man page for echo on your system. Here is a more
readable output of the usage statement that demonstrates the formatting:
Usage:

jkl [-lf:bmcdxh]
[-h] This usage text.
[-f] cat specified file.
[-l] Go to application log directory with ls.
[-b] Go to application bin directory.
[-c] Go to application config directory.
[-m] Go to application log directory and more log file.
[-d] Turn on debug information.
[-x] Turn off debug information.
Then you define the software version numbers based on the information found in the
application configuration file, as in the following code:
major=`egrep "^MAJOR_VER=" $MYAPP_ID | cut -d"=" -f2`
minor=`egrep "^MINOR_VER=" $MYAPP_ID | cut -d"=" -f2`
dot=`egrep "^DOT_VER=" $MYAPP_ID | cut -d"=" -f2`
This file isn’t shown in this example, but you can assume that these values are in
that file. The file is included in the downloadable script package in the Source Code/
Download area of the Apress web site (www.apress.com).
The names of the various application directories are formed from the combination of
application names and version-number variables. Here we assign the directory variables
their values.
APPDIR=$APPHOME/myapp.$major.$minor.$dot
LOGDIR=$APPHOME/myapp.$major.$minor.$dot/log
CFGDIR=$APPHOME/myapp.$major.$minor.$dot/config
BINDIR=$APPHOME/myapp.$major.$minor.$dot/bin
Then we check to see if any command-line switches were used when the function was
called. If none are found, the usage statement should be displayed. Note that the echo
command uses the -e switch, which enables the use of the escape sequences found in the
Usage variable.
if [ "$#" -lt 1 ]
then

echo -e $Usage
fi
34
CHAPTER 5

ACCEPTING COMMAND-LINE OPTIONS, SWITCHES, AND PARAMETERS
If the script did not use the -e switch, it would not format the output properly, instead
printing the escape sequences along with the usage information.
User-supplied options are accessed through an argument vector, or what you may
think of as an array. The getopts utility uses the OPTIND environment variable to index this
array. Each time the example code function is invoked, the variable needs to be reset to 1
before option processing starts in order to point at the beginning of the options that have
been passed.
OPTIND=1
As the while loop in the following code snippet iterates through the passed options, the
getopts utility increments the value of the OPTIND variable and processes through any
parameters that were passed.
This while loop is the core of the script. It is where the passed parameters are processed
and appropriate actions are taken.
while getopts lf:bmcdxh ARGS
do
case $ARGS in
l) if [ -d $LOGDIR ] ; then
cd $LOGDIR
/bin/ls
fi
;;
f) FILE=$OPTARG
if [ -f $FILE ]
then

cat $FILE
else
echo $FILE not found. Please try again.
fi
;;
b) if [ -d $BINDIR ] ; then
cd $BINDIR
fi
;;
m) if [ -d $LOGDIR ] ; then
cd $LOGDIR
/bin/more $APPLOG
fi
;;
c) if [ -d $CFGDIR ] ; then
cd $CFGDIR
fi
;;
d) set -x
;;
CHAPTER 5

ACCEPTING COMMAND-LINE OPTIONS, SWITCHES, AND PARAMETERS
35
x) set +x
;;
h) echo -e $Usage
;;
*) echo -e $Usage
;;

esac
done
}
The getopts command is invoked with a list of the valid switches, which it parses
to determine which switches need arguments. Each time getopts is invoked, it checks
whether there are still switches to be processed. If so, it retrieves the next switch (and
updates the value of OPTIND), stores it in the specified environment variable (here, ARGS),
and returns true. Otherwise, it returns false. In this way, the while loop iterates through
the options vector. Each time the shell executes the loop body, the case statement
applies the actions that the current option requires.
In this case, most of the options take you to an application-specific directory. The three
most interesting cases here are the -d, -x, and -f switches. The -d switch turns on com-
mand expansion and the -x switch turns it off. This is very useful and an easy method for
debugging scripts. The -f switch is different from the rest. Note that it has a colon (:)
following the f in the getopts switch list. If a switch is followed by a colon, an argument
should follow the switch when it is used. In our example, the -f switch lists the contents
of a file and requires the filename to follow. The case branch for -f sets the FILE variable
to $OPTARG. This is another special environment variable that is set by getopts to assign the
argument that is passed to the switch. If the file exists, it will be displayed; if not, the code
will generate an error message.
The last two switches cause the usage statement to be displayed. A more advanced
example of the getopts construct can be found in Chapter 17. Additionally, I have
included another script in the download package for this chapter (at www.apress.com) that
performs some basic administrative tasks, including turning on and off the set -x value.

×