As mentioned in chapter 5, the terms argument and parameter are sometimes used interchangeably in both OS/400 and Unix. However, in this book, we try to be precise in the use of these and related terms:
Command-line arguments follow a command name. They control the behavior of a script or supply additional information to a script. Arguments are separated from the command name , and from one another, by white space. In the following example, three arguments are supplied to myscript.qsh:
myscript.qsh -n -o mydata.dat
Notice the two options that begin with hyphens. Options are typically used to control the behavior of a script, whereas other arguments ("non-options") supply data values to the script.
In script programming, the order in which the options are specified on the command line should not matter. For example, both of the following commands should produce the same results:
myscript.qsh -n -o mydata.dat myscript.qsh -o -n mydata.dat
Options can also be grouped together behind one hyphen, so the following commands should be equivalent to the previous two:
myscript.qsh -no mydata.dat myscript.qsh -on mydata.dat
It is up to you, the programmer, to make sure a script can handle any of these forms.
It is also common in Unix shell programming to permit the use of a double hyphen (--) to indicate the end of the options and the beginning of the "non-options." In the following example, the n option is specified. The value mydata.dat is an argument, but it is not an option argument:
myscript.qsh -n - mydata.dat
In Figure 11.1, the first print command fails because the value of c , -3, is interpreted as an option. The second print succeeds because the double hyphen tells Qshell that the remaining arguments on the command line are not to be interpreted as options.
a=5 b=7 /home/JSMITH $ let c=a-b /home/JSMITH $ print $c print: 001-0036 Option 2 is not valid. /home/JSMITH $ print -- $c -2
Figure 11.1: Qshell might mistake negative numbers for options.
An option may also take an argument of its own. Consider the following example:
myscript.qsh -n -f mydata.dat -p mydata.prn -z
Four options are passed to the script: n , f , p , and z . The f option takes the argument mydata.dat . The p option takes the argument mydata.prn . The n and z options do not take arguments of their own.
When you write a script, you have to consider two things about arguments:
The following sections present three cases that illustrate these issues.
The easiest case is when there is a fixed number of arguments and none of them are options. In this case, the meaning of each argument is determined by its position in the list. For example, the following two commands are not equivalent because the order of the arguments determines their meaning:
myscript.qsh mydata.dat yourdata.dat myscript.qsh yourdata.dat mydata.dat
When the script begins, use the special parameter $# to be sure the correct number of arguments was passed. If there were too few or too many, send a message to stderr and exit with a non-zero status code.
The following example verifies that exactly three arguments are passed to the script:
# make sure correct number of arguments was passed if [ "$#" -ne 3 ] then echo "Usage: ${0#$PWD/} pattern fromfile tofile" >&2 exit 1 fi
If too many or two few arguments are passed to the script, the script sends an error message to stderr and exits with an exit status of 1.
It is likewise easy to handle the situation in which there is a variable number of arguments and none of them are options. You must test the parameters and take action accordingly . The best way to test for the presence of absence of an argument is with the n and z options of the extended conditional expression.
In the following example, Qshell writes the value of variable somevar to the file named in the second parameter if this parameter has a length that is not zero (i.e., at least two arguments were passed to the script):
if [[ -n "" ]] then echo $somevar > fi
If the user passed only one argument, the echo would not be carried out.
If your release supports it, use the extended conditional construct with the n conditional option. There are two reasons for this. First, the extended conditional is faster than the test utility. Second, when used in test , the variable expansion must be in double quotes for this code to work correctly. If the double quotes are omitted, the expression will prove true whether or not the second parameter has a value, as in this example:
if [ -n ] # < ----- ERROR !!!!!!! then echo $somevar > fi
If parameter 2 is b , the expression evaluates to [ -n b ], which proves true. If parameter 2 has no value, the expression evaluates to [ -n ], which also proves true. To avoid this problem, surround the parameter-substitution expression in double quotes.
Here's another example. Up to 255 arguments may be passed to the following script:
while [ ] do cp .bu shift done
Each argument should be a file name . Each file is copied to another file, whose name is the same, but with a suffix of .bu . For example, file xyz.txt is copied to file xyz.txt.bu.
The last case to consider is that of using options. Options must precede the non-option arguments. The usual method for handling options is to process the option arguments first, shift them out, then process the remaining arguments, as in the previous two cases.
This is a task you should not attempt to do by hand. There are two possibilities to consider, which makes for messy programming:
myscript.qsh -dx myscript.qsh -d -x myscript.qsh -xd
myscript.qsh -f somefile.txt myscript.qsh -fsomefile.txt
The getopts utility makes easy work of processing the options. Here is its syntax:
getopts option-string variable
The option string lists the expected options, with no preceding hyphen. Follow an option that takes an argument of its own with a colon (:). For example, the following script is written to expect five options: b , c , d , k , and t . The d and t options are expected to be followed by arguments of their own:
while getopts bcd:kt: argname
Each time getopts is executed, Qshell returns another option from the command line. The name of the option is stored in the variable without a preceding hyphen. For example, the short script arglist.qsh in Figure 11.2 does nothing but list the options that are passed to it.
cat arglist.qsh while getopts vf:l option do echo $option done /home/JSMITH $ arglist.qsh -vl v l /home/JSMITH $ arglist.qsh -v -l v l /home/JSMITH $ arglist.qsh -l -f mydata.csv l f
Figure 11.2: The getopts utility makes easy work of extracting options and their arguments.
If the option is expected to have an argument, that argument's value is stored in the special variable OPTARG. If an option is not expected to have an argument following it, the value of OPTARG is undefined . Figure 11.3 shows the use of the OPTARG variable. The arglist.qsh script has been modified to list the OPTARG variable. The value of OPTARG is not defined for option l ("ell").
cat arglist.qsh while getopts vf:l option do echo $option $OPTARG done /home/JSMITH $ arglist.qsh -l -f mydata.csv 1 f mydata.csv /home/JSMITH $ arglist.qsh -f mydata.csv -l f mydata.csv l mydata.csv
Figure 11.3: The getops utility places an option's argument into variable OPTARG .
You do not have to leave white space between an option and its argument, but doing so can promote readability. In Figure 11.4, the f option is separated from its argument in the first invocation of arglist.qsh, but not separated from its argument in the second invocation.
cat arglist.qsh while getopts vf:l option do echo $option done /home/JSMITH $ arglist.qsh -f mydata.csv f mydata.csv /home/JSMITH $ arglist.qsh -fmydata.csv f mydata.csv
Figure 11.4: Qshell allows you to leave white space between an option and its argument, but does not require you to do so.
OPTIND is another option- related special variable that you will need. Qshell uses OPTIND to keep up with its place while working through the list of options. After Qshell has finished processing all the options, OPTIND will have a value one greater than the number of arguments in the option list. For that reason, shifting OPTIND minus one argument removes all the options.
The script in Figure 11.5 permits three options: v , f , and p . The f option is to be followed by a file name. One or more non-option arguments may follow the options.
# process the options vflag=off pflag=off while getopts vf:p argname do case $argname in v) vflag=on;; p) pflag=on;; f) filename=$OPTARG;; *) print -u2 "Usage: $(basename
# process the options vflag=off pflag=off while getopts vf:p argname do case $argname in v) vflag=on;; p) pflag=on;; f) filename=$OPTARG;; *) print -u2 "Usage: $(basename $0): [-vp] [-f file] [-] file ..." exit 1;; esac done # get rid of options shift $OPTIND-1 # At this point, the settings of the v and p options # are in variables vflag and pflag, the argument to the f option # (if it was specified) is in variable filename, and the first # non-option argument is in positional parameter 1.
): [-vp] [-f file] [-] file ..." exit 1;; esac done # get rid of options shift $OPTIND-1 # At this point, the settings of the v and p options # are in variables vflag and pflag, the argument to the f option # (if it was specified) is in variable filename, and the first # non-option argument is in positional parameter 1.
Figure 11.5: It is customary to shift out the options after having processed them.
Two variables, vflag and pflag , are initialized to the value off . The while loop extracts the options. As each argument is processed, the case structure modifies at most one variable. The vflag and pflag variables are changed to on if the v and p options are specified. If the f option is found, Qshell copies the following argument, which is in variable OPTARG, into the variable filename . The shift utility drops the options, so that the first positional parameter contains the first non-option argument.
If an invalid option is entered, the last case, the wildcard character (the asterisk), is matched. The script sends a message to stderr reminding the user of the proper usage and exits with a status of 1.
If getopts encounters an option that is not listed in the option list, or does not find an argument to an option that is followed by a colon in the option list, it sends an error to stderr. This is illustrated in Figure 11.6.
cat arglist.qsh while getopts vf:l option do echo [$option] $OPTARG done /home/JSMITH $ arglist.qsh -v -w -f [v] getopts: 001-0036 Option w is not valid. [?] getopts: 001-0038 Required argument for option f is not specified. [?]
Figure 11.6: The getopts utility replaces invalid options with a question mark and sends error messages to stderr.
Be aware that errors were originally sent to standard output. In V5R2, this was changed by a PTF so that errors would be sent to the standard error file, as occurs in Unix shells .
Qshell programming relies on the presence of option and non-option arguments to control the behavior of scripts and supply scripts with necessary data values. Qshell programmers should write scripts that conform to the customary standards for passing arguments. The getopts utility provides an easy way to extract arguments from a command invocation.
Preface