Previous | Table of Contents | Next |
To get a feeling for how getopts works and how to deal with options, write a script that simplifies the task of uuencoding a file.
For readers who are not familiar with uuencode, it is a program that was originally used to encode binary files (executable files) into ASCII text so that they could be emailed or transferred via FTP. Today, MIME encoding has taken the place of uuencoding for email attachments, but it is still used for posting binaries to newsgroups and transferring them via modem.
Youll first examine the interface of this script, which makes it easier to understand the implementation.
This script should be able to accept the following options:
The getopts command to implement these requirements is
getopts e:o:v OPTION
This indicates that all the options expect for v to require an additional parameter. The variables you require in order to support this are
The loop to implement the preceding requirements is as follows:
VERBOSE=false while getopts f:o:v OPTION ; do case "$OPTION" in f) INFILE="$OPTARG" ;; o) OUTFILE="$OPTARG" ;; v) VERBOSE=true ;; \?) echo "$USAGE" ; exit 1 ;; esac done
Now that you have dealt with option parsing, you need to deal with still other error conditions. For example, what should your script do if the input file is not specified?
The simplest answer would be to exit with an error, but with a little more work, you can make the script much more user-friendly. If you use the fact that getopts sets the variable OPTIND to the value of the last option that it scanned, you can have the script assume that the first argument after this is the input filename. If no additional arguments remain, you should exit. Your error checking consists of the following lines:
shift `echo "$OPTIND - 1" | bc` if [ -z "$1" a z "$INFILE" ] ; then echo "ERROR: Input file was not specified." exit 1 fi if [ -z "$INFILE" ] ; then INFILE="$1" ; fi
Here you use the shift command to discard the arguments given to the script by one minus the last argument processed by getopts. The exact number of arguments to shift is calculated by the bc command, which is a command line calculator. Its usage is explained in detail in Chapter 18, Miscellaneous Tools.
Strictly speaking, you do not have to shift the arguments. It simplifies the if statement.
After shifting the arguments, check whether the new $1 contains some value. If it does not, print and exit. Otherwise, set INFILE to the filename specified by $1.
You also need to set the output filename, in case the o option was not specified. You can use variable substitution to accomplish this:
: ${OUTFILE:=${INFILE}.uu}
Here the name of the output file is set to the input file plus the .uu extension, if an output file is not given. Note that you use the : command to prevent the shell from trying to execute the result of the variable substitution.
When you have made sure that all the inputs are correct, the actual work is quite simple. The uuencode command that you use is:
uuencode $INFILE $INFILE > $OUTFILE ;
You should also check whether the input file is really a file before doing this command, so the actual body is
if [ -f "$INFILE" ] ; then uuencode $INFILE $INFILE > $OUTFILE ; fi
At this point the script is fully functional, but you still need to add the verbose reporting. This changes the preceding if statement to the following:
if [ -f "$INFILE" ] ; then if [ "$VERBOSE" = "true" ] ; then echo "uuencoding $INFILE to $OUTFILE... \c" fi uuencode $INFILE $INFILE > $OUTFILE ; RET=$? ; if [ "$VERBOSE" = "true" ] ; then MSG="Failed" ; if [ $RET -eq 0 ] ; then MSG="Done." ; fi echo $MSG fi fi
You could simplify the verbose reporting to print a statement after the uuencode completes, but issuing two statements, one before the operation starts and one after the operation completes, is much more user-friendly. This method clearly indicates that the operation is being performed.
The complete script is as follows:
#!/bin/sh USAGE="Usage: `basename $0` [-v] [-f] [filename] [-o] [filename]"; VERBOSE=false while getopts f:o:v OPTION ; do case "$OPTION" in f) INFILE="$OPTARG" ;; o) OUTFILE="$OPTARG" ;; v) VERBOSE=true ;; \?) echo "$USAGE" ; exit 1 ;; esac done shift `echo "$OPTIND - 1" | bc` if [ -z "$1" -a -z "$INFILE" ] ; then echo "ERROR: Input file was not specified." exit 1 fi if [ -z "$INFILE" ] ; then INFILE="$1" ; fi : ${OUTFILE:=${INFILE}.uu} if [ -f "$INFILE" ] ; then if [ "$VERBOSE" = "true" ] ; then echo "uuencoding $INFILE to $OUTFILE... \c" fi uuencode $INFILE $INFILE > $OUTFILE ; RET=$? if [ "$VERBOSE" = "true" ] ; then MSG="Failed" ; if [ $RET -eq 0 ] ; then MSG="Done." ; fi echo $MSG fi fi exit 0
With this script you can uuencode files in all of the following ways (assuming the script is called uu):
uu ch11.doc uu f ch11.doc uu f ch11.doc o ch11.uu
In each of the preceding examples, file ch11.doc is uuencoded. The last one places the result into the file ch11.uu instead of the default ch11.doc.uu, which might be required if the document needs to be used on a DOS or Windows system.
Because this script uses getopts any of the commands given previously can run in verbose mode by simply specifying the v option.
Previous | Table of Contents | Next |