Parameters and Variables, Defined
Just as you can pass parameters to RPG programs, CL programs, and OCL procedures, you can pass parameters, or arguments , to Qshell scripts. Strictly speaking, an argument is a value that is passed to a script or program, while a parameter is a variable defined in a program to represent the argument. However, it is common in iSeries and AS/400 computing to use the word parameter to mean both parameters and arguments. In this book, we try to use the words according to their strict meanings, although even we might occasionally slip up, referring to an argument as a parameter. (There are certainly much worse crimes we could be guilty of.) The important thing to note is that parameters are passed by position, never by keyword.
Command Line Arguments
Command-line arguments follow a command name. They are separated from the command name and from one another by white space, i.e., blanks and/or tabs. (Although you can't type tabs in an interactive Qshell session, a script that was entered from a text editor on another machine might include them.)
The following line of code shows how to run a Qshell script, passing two arguments to it:
myscript.qsh home jsmith
If an argument includes blanks, surround it with single quote (') or double quote (") marks. For example, either of the following two command lines would work to pass three arguments, two of which contain embedded blanks:
myscript.qsh 'New York' Chicago 'Los Angeles' myscript.qsh "New York" Chicago "Los Angeles"
If an argument includes a single quote or double quote, precede the character with a backslash (), like this:
myscript.qsh Eat at Joe's # Eat a Joe's myscript.qsh 48" # 48" (48 inches)
You may also embed one type of quote within quotes of the other type, as shown here:
myscript.qsh "Eat at Joe's" # Eat a Joe's myscript.qsh '48"' # 48" (48 inches)
Retrieving Parameter Values
A script can refer to parameters in one of two ways. The simple form is $ n . In most cases, this form is adequate, but in cases of ambiguity, braces are added, in the form ${ n }. In both forms, n represents a number in the range from 1 to 255.
To understand the use of these two forms, consider the following two expressions:
# the twelfth positional parameter 2 # the first positional parameter followed by the character 2
The first expression refers to the value of the twelfth positional parameter. The second refers to the first positional parameter, with the digit 2 appended to it. If the first argument has the value go and the twelfth argument has the value mydata.csv , the expressions yield the values mydata.csv and go2 .
Here is a one-line script that uses two positional parameters:
cd //
To run the script, you would use a command like this:
myscript.qsh home jsmith
Notice that the arguments are separated by white space. The script would run the following cd command:
cd /home/jsmith
Qshell replaces the parameter markers with their values before interpreting the command. This means that commands themselves may be stored in positional parameters.
In Figure 5.1, the print command shows that the first positional parameter contains the string ls . Qshell replaces the parameter $1 with the value ls , no matter where in a command Qshell finds the string.
print ls /home/JSMITH $ arglist.qsh fix2.qsh select01.qsh bin fix3.qsh tema bu.qsh ftpmodel.txt temp.txt
Figure 5.1: Execution of commands takes place after substitution, which means a command name may be stored in a positional parameter.
Preventing Parameter Substitution
There are two ways to prevent Qshell from substituting a parameter value for a parameter expression. One is to precede the dollar sign with a backslash. The other is to surround the parameter expression with single quotes.
For instance, consider the short terminal session history shown in Figure 5.2. The first two commands print the fifth positional parameter, which has a value of 24. The last two commands print the string $5.
> print 24 > print "" 24 > print $5 > print ''
Figure 5.2: Single quotes and backslashes prevent interpretation of the dollar sign.
Single quotes are often called strong quotes , because they protect the contents of the quoted expression from interpretation. In contrast, double quotes are often called weak quotes .
The Set Utility
You can use the set utility to assign values to the positional parameters from within a Qshell script. In the following example, the current values of all 255 positional parameters are discarded. The first four parameters are then assigned the values listed in the arguments:
set MYLIB MYFILE MYMBR .csv
To discard the values of all 255 positional parameters without specifying new values, use two hyphens as the argument to set :
The Shift Utility
The shift utility reassigns the positional parameters. By default, Qshell moves each parameter one position to the left. That is, parameter 2 is copied to parameter 1, parameter 3 is copied to parameter 2, parameter 4 is copied to parameter 3, etc. The value of parameter 1 is lost.
This ability makes shift particularly well suited for processing all the parameters, one at a time. For example, a script performs a loop to process parameter 1 and then uses the shift utility. If parameter 1 is still set, it repeats the loop.
In Figure 5.3, the first parameter is shifted out of the parameter list.
set a b c d e f g /home/JSMITH $ print a b c d e f g /home/JSMITH $ shift /home/JSMITH $ print b c d e f g
Figure 5.3: No parameter is passed to the shift utility, so one parameter is shifted out of the list.
You may follow shift with one argument to tell it how many parameters to shift out of the parameter list. Figure 5.4 shows the parameters shifted four places left. The values of parameters 1 through 4 are discarded.
set a b c d e f g /home/JSMITH $ print a b c d e f g /home/JSMITH $ shift 4 /home/JSMITH $ print e f g /home/JSMITH $
Figure 5.4: In this example, the shift utility shifts the parameters four positions .
If the argument is zero or negative, the shift utility does not reassign the parameters. If the argument is larger than the number of defined parameters, Qshell responds with message number 001-0058. This message number means "Number of positional parameters to shift must be less than n ," where n is the number of defined parameters.
Special Parameters
Qshell has eight special parameters, listed in Table 5.1. You do not have to define these parameters or load any values into them.
Parameter |
Description |
---|---|
$0 (zero) |
Name of shell or shell script |
$# |
Number of positional parameters |
$$ |
Process ID |
$! |
Background-process ID |
$? |
Exit status |
$- |
Option flags |
$* |
Positional parameters |
$@ |
Positional parameters |
You may surround the second character with braces if you wish. That is, both $0 and ${0} return the shell or script name. Most of these parameters are discussed in detail in this and later chapters. For example, the $? parameter is discussed in chapter 7.
The Difference between $* and $@
Both $* and $@ return the list of positional parameters, but how they return the parameters depends on whether they are unquoted or within double quotes. (Within single quotes, they are not expanded.) Here are the rules:
- When $* and $@ are not quoted, they expand to the list of parameters. Embedded blanks are not preserved.
- When $* is double-quoted, all the parameters are returned as a single argument.
- When $@ is double-quoted, the parameters are returned separately, with embedded blanks preserved. Therefore, "$@" is equivalent to "$1," "$2," "$3," and so on.
Generally, use the following format when referring to all positional parameters:
"$@"
Use another form only when you specifically need a different behavior.
To illustrate , suppose that three positional parameters have been defined with the values Joe Smith , mydata.txt , and 12 , respectively. As shown in Figure 5.5, if you ask Qshell how many parameters are defined, you are told that there are three positional parameters with values. Furthermore, the first parameter has the value Joe Smith .
print $# 3 print Joe Smith
Figure 5.5: Three positional parameters have been set. The first has an embedded blank. separated by spaces.
Remember that $* and $@ exhibit the same behavior when not quoted. Both return the positional parameters separated by spaces, as shown in Figure 5.6.
print $* Joe Smith mydata.txt 12 print $@ Joe Smith mydata.txt 12
Figure 5.6: Without quotation marks, both $* and $@ return the list of parameters
Figure 5.7 demonstrates the use of these special parameters in single quotes. As you can see, $* and $@ do not return the same value, because single quotes prohibit parameter substitution.
print '$*' $* print '$@' $@
Figure 5.7: Strong quotes prevent parameter expansion.
Figure 5.8 shows the difference between $* and $@ when double-quoted. (The for loop is covered in chapter 8. At this point, just be aware that for executes a print command for each positional parameter.) Notice that $* returns all positional parameters as one value, while $@ returns the positional parameters separately.
for file in "$*" ; do print $file ; done Joe Smith mydata.txt 12 for file in "$@" ; do print $file ; done Joe Smith mydata.txt 12
Figure 5.8: Within double quotes, $* returns all parameters as one argument, but $@ maintains the individual parameter values.
Unshifting Parameters
You can use the double-quoted $ @ parameter to implement the counterpart of shift . That is, you can insert new parameters at the beginning of the parameter list, shifting existing parameters to the right.
Figure 5.9 illustrates this technique. The first echo command shows that five positional parameters are set, with values a, b, c, d, and e . The set command replaces the positional parameters with the value z and the existing values of the positional parameters. The second echo shows the new values of the positional parameters. This is the opposite of shift . A new parameter 1 is defined, and all existing parameters are shifted right, instead of left.
set a b c d e /home/JSMITH $ echo $#: "$@" 5: a b c d e /home/JSMITH $ set z "$@" /home/JSMITH $ echo $#: "$@" 6: z a b c d e
Figure 5.9: You can use "$@" to insert new parameters at the beginning of the list, shifting existing parameters right.
Qshell Variables
A variable name begins with a letter or underscore (_), which is followed by any combination of letters , digits, and underscores. If you spell the same variable two different ways, Qshell will think you are using two different variables. Variable names are case sensitive, so DOG, Dog, dOG, and dog are four different variables.
Variable Declaration
You create a variable by assigning a value to it:
variable=value
Leave no blanks on either side of the equal sign. If you leave a blank in front of the equal sign, Qshell looks for a command or script with the name of the variable. If you leave a blank after the equal sign, Qshell assigns a null value to the variable. If the value contains blanks, enclose it in either single quotes or double quotes. The quotes are not part of the value.
The following lines of code illustrate the creation of a variable:
thisvar=/home/jsmith thisvar="/home/jsmith" thisvar=
The first two assignments are equivalent. In both cases, the value of thisvar is /home/jsmith. After the third assignment, thisvar has a null value.
Two or more variables may be created in a single statement by separate the assignments with white space, like this:
i=0 max=24 name=Jack
In this example, variables i , max , and name are defined.
Untyped versus Typed Data
By default, Qshell variables are untyped. That is, the same variable can contain character or numeric data at different times, as Figure 5.10 demonstrates .
age="Reason" /home/JSMITH $ print $age Reason /home/JSMITH $ age=49 /home/JSMITH $ print $age 49
Figure 5.10: The same variable, age , contains character data and numeric data at different times.
In V5R2, IBM added the declare utility, which lets you define the type of data that a variable should contain. This is called strongly typing a variable. An alternate name for declare is typeset . Declare utility comes from the bash shell, while typeset comes from the Korn shell. Supporting both names helps with porting shell scripts from other systems. Supposedly, declare is the preferred form.
The syntax of the declare command is as follows :
declare [ option ] name [ =value ]
The supported data types are listed in Table 5.2.
Option |
Description |
---|---|
E |
Floating point |
i |
Integer |
l (ell) |
Lowercase character |
u |
Uppercase character |
Figure 5.11 shows one way to declare typed variables. Figure 5.12 is equivalent to Figure 5.11, but uses typeset instead of declare .
name="Joe Smith" /home/JSMITH $ declare -u uname="$name" /home/JSMITH $ declare -l lname="$name" /home/JSMITH $ print $name '' $uname '' $lname Joe Smith JOE SMITH joe smith
Figure 5.11: The variable name may contain any type of data. The data in variables uname and lname will be stored in uppercase and lowercase, respectively.
name="Joe Smith" /home/JSMITH $ typeset -u uname="$name" /home/JSMITH $ typeset -l lname="$name" /home/JSMITH $ print $name '' $uname '' $lname Joe Smith JOE SMITH joe smith
Figure 5.12: The typeset utility is an alternate form of declare .
If you do not list any variables in the command line, declare (or typeset ) lists the variables that have been defined with that type, as shown in Figure 5.13.
declare -u declare -u uname="JOE SMITH" /home/JSMITH $ declare -l declare -l lname="joe smith"
Figure 5.13: Since no variables are declared, the declare utility lists the variables of the indicated type.
You may declare more than one variable at a time. You may also initialize one or more of the variables during declaration, as shown in Figure 5.14.
declare -i i=10 j=20 k l=40 /home/JSMITH $ declare -i declare -i i="10"" declare -i j="20" declare -i k="" declare -i l="40" /home/JSMITH $
Figure 5.14: This example shows how to declare four integer variables and initialize three of those variables with one command.
When using typed variables, however, be careful to initialize them to the proper values for their types. Assigning invalid values to typed variables leads to unpredictable results, as shown in Figure 5.15.
typeset -i age=46.5 typeset: 001-0032 Number 46.5 is not valid. /home/JSMITH $ typeset -i declare -i age="46.5" /home/JSMITH $ print $age 46.5 /home/JSMITH $ let age=age*2 let: 001-0032 Number 46.5 is not valid. /home/JSMITH $ print $age 46.5
Figure 5.15: The value 46.5 is not compatible with the integer data type, so Qshell does not recognize the value of age as a number.
Aliases for Data Types
An alias is an alternate name, usually a shortcut, for a command string. Typing an alias name is equivalent to typing the command string the alias represents. In V5R2, Qshell predefines aliases for two data types:
alias float='declare -E' alias integer='declare -i'
Figure 5.16 shows variables defined according to these alias definitions.
integer age=35 /home/JSMITH $ integer declare -i age="35" /home/JSMITH $ float temp=98.6 gun=30.06 /home/JSMITH $ float declare -E gun="30.06" declare -E temp="98.6"
Figure 5.16: The integer and float aliases have been used instead of declare.
Read Only Variables
If you precede a variable assignment with readonly , the script will not be able to change its value. An example of this is shown in Figure 5.17.
readonly filename=JoesData.CSV /home/JSMITH $ filename=BillsData.CSV qsh: 001-0065 Variable 1$.*s is read-only and cannot be changed. /home/JSMITH $ readonly filename=JimsData readonly: 001-0065 Variable 1$.*s is read-only and cannot be changed.
Figure 5.17: The variable filename is defined as a read-only variable, so its value cannot be changed.
Under V5R2, you can use the -r option of the declare and typeset utilities to set the read-only attribute of a variable, as shown in Figure 5.18.
typeset -r filename=JoesData.CSV /home/JSMITH $ filename="BillsData.CSV" qsh: 001-0065 Variable 1$.*s is read-only and cannot be changed.
Figure 5.18: The -r option of declare and typeset set the read-only attribute.
Running readonly without parameters lists the defined read-only variables.
Retrieving the Value of a Variable
To retrieve the value of a variable, precede its name with a dollar sign. Think of the dollar sign as meaning "the value of." Figure 5.19 shows how to retrieve a variable's value. The first print statement does not return the value of the name variable because the dollar-sign prefix has been omitted.
name=Jack /home/JSMITH $ print name name /home/JSMITH $ print $name Jack
Figure 5.19: You need the dollar-sign prefix to return a variable's value.
If you prefer, you may enclose the variable name within braces, but the dollar sign is still required as a prefix. Braces are required when another value follows the variable name with no intervening white space. This alternate syntax is illustrated in Figure 5.20.
name=Jack /home/JSMITH $ print $name Jack print ${name} Jack /home/JSMITH $ print ${name}et Jacket
Figure 5.20: You do not have to surround a variable name with braces except when the variable name abuts another value.
Unset Variables and Null Values
A variable may be unset, or a variable may be set to a null value. There is a difference. A variable with a null value exists, but has no value. Or, if you prefer, it has a zero-length value. An unset variable, on the other hand, is not defined.
Qshell usually ignores the difference between unset and null values, but you can make it distinguish between them, if you wish. To undefine a variable that has previously been defined, use the unset utility, as shown in Figure 5.21.
print $name Jack /home/JSMITH $ unset name /home/JSMITH $ print $name /home/JSMITH $
Figure 5.21: Use the unset utility to undefine a previously defined variable.
By default, Qshell does not mind if you use variables that have not been defined. If you misspell the name of a variable name, Qshell doesn't complain, but returns the null value. If you want Qshell to return an error when it encounters an undefined variable, use the set utility, specifying either -u or -o nounset . Then, when you ask Qshell to retrieve the value of an unset variable, Qshell will send message 001-0021 to the standard error file (stderr), as shown in Figure 5.22.
set -u # or set -o nounset /home/JSMITH $ name=Jack /home/JSMITH $ print $neme qsh: 001-0021 Parameter 1$.*s is not set.
Figure 5.22: Qshell can be set to send an error message when an undefined variable is referenced.
Predefined Variables
Qshell predefines several variables, which it uses for two purposes:
- To pass session settings to scripts
- To store session information
Table 5.4 lists some of the predefined variables. They are covered in detail in later chapters.
Variable |
Description |
---|---|
JOBNAME |
Qualified job name |
LINENO |
Line number |
OLDPWD |
Previous working directory |
PWD |
Working directory |
RANDOM |
Random number generator |
UID |
User identifier |
CDPATH |
Search path for cd |
ENV |
Environment file |
HOME |
Home directory |
IFS |
Internal field separators |
PATH |
Search path for commands |
PS1 |
Primary prompt string |
PS2 |
Secondary prompt string |
Even though you do not declare these variables, you can use them as you would your own. Normally, you retrieve the values of predefined variables, but you do not change them. Figure 5.23 illustrates the use of the $RANDOM predefined variable.
i=0 ; while [ $i -lt 9 ] ; do print $RANDOM ; let "i=i+1" ; done 2656 684 13708 49702 58934 31462 46746 21854 48842
Figure 5.23: Use $RANDOM to retrieve a random number.
In Figure 5.24, the $HOME predefined variable is used. The user is working from the /home/JSMITH directory. The first cd command changes to source physical file SRC in library MYLIB. The cp command copies source member MATH to an IFS file in the user's home directory. The second cd changes back to the home directory. The ls command verifies that the copy was successful.
/home/JSMITH $ cd /qsys.lib/mylib.lib/src.file /qsys.lib/mylib.lib/src.file $ cp MATH.MBR $HOME /qsys.lib/mylib.lib/src.file $ cd ~ /home/JSMITH $ ls M* MATH.MBR MkXYZ.java /home/JSMITH $
Figure 5.24: Use $HOME to refer to the home directory.
Summary
You may define parameters and variables to hold data values. There are two types of parameters:
- Positional parameters are accessed by an ordinal number.
- Predefined parameters are those to which the system assigns values.
There are also two types of variables: those whose names are already defined to Qshell, and those whose names you must assign. Before V5R2, variables were not types. As of V5R2, you may assign a data type to a variable if you wish. You may also use the readonly utility to specify that a variable's value is unchangeable. You create a variable by assigning a value to it, or by declaring it with the declare or typeset utility.