Previous Table of Contents Next


User-Defined Functions

You can write your own functions in the Bourne and Korn shells and use them as part of other scripts.


NOTE:  Not all Bourne shells support functions. However, the Solaris 2.x Bourne shell supports functions.

User-defined functions are useful if you have a series of commands that you want to use repeatedly. The functions written for an application server are an example of user-defined functions. Some examples of functions are provided in the section "Example Scripts" in Chapter 17. When you define a function, you use the name of the function at the place where you want to execute the series of commands contained in the function.

Typically, you define functions at the beginning of a script, but you can define them in separate files and share them between scripts. Once the function has been defined, you can use it any number of times.

Use the following syntax to define functions:

function_name() {
    (body of the function)
}

Shell functions use positional parameters and special variables such as * and # in the same way that shell scripts do. Typically, you define several shell functions within a single shell script. Each function receives arguments as positional parameters. These positional parameters "overlay" command-line parameters.

To call the function, use the function_name as if it were a normal command at the place in the script where you want to use the function. The following Bourne shell script defines and uses a simple function:

#!/bin/sh
#
printlist() {
        echo The current list of arguments is:
        echo $*
}
while [ $# -gt Ø ]
do
        printlist $*
        shift 2
done

The following example shows the result of running this script:

oak% doit one two three four
The current list of arguments is:
one two three four
The current list of arguments is:
three four
oak%

Debugging Shell Scripts

The following sections provide some suggestions for debugging shell scripts.

Using Debugging Flags

A common problem when writing shell scripts is that the shell does not interpret the command in exactly the way that you expect. When the shell interprets a command line, it substitutes variables with values, replaces filename wildcards with the appropriate file names, and performs command substitution. If the interpretation transforms a command line into something unexpected, the command most likely will not execute the way you intend for it to.

All three shells provide -x (echo) and -v (verbose) options that you can use to help pinpoint where problems are occurring in a script. The -v option displays each line of the script as it is read from the file. The -x option shows each line after it has been processed by the shell and is ready for execution. The combination of these two options provides you with much useful information for debugging your scripts.

You can use the options from the command line, as shown:

oak% csh -xv script-name
$ sh -xv script-name
$ ksh -xv script-name

Alternatively, you can set the flag options in the first line of the script, as follows:

#!/bin/sh -xv
#!/bin/csh -f -xv
#!/bin/ksh -xv

The following example shows the time-of-day greeting script with the -x option in the command line, followed by the screen output:

#!/bin/sh -x
#
# Time of day greetings
#
hour=`date +%H`

if [ $hour -le 12 ]
then
        echo "Good Morning!"
elif [ $hour -le 17 ]
then
        echo "Good Afternoon!"
else
        echo "Good Night!"
fi

$ greetings
+ date +%H
hour=11
+ [ 11 -le 12 ]
+ echo Good Morning!
Good Morning!
$

The following example shows the output for the same script with the -v option set:

$ greetings
#!/bin/sh -v
#
# Time of day greetings
#
hour=`date +%H`

if [ $hour -le 12 ]
then
        echo "Good Morning!"
elif [ $hour -le 17 ]
then
        echo "Good Afternoon!"
else
        echo "Good Night!"
fi
Good Morning!
$

The following example shows the screen output of the same script with -xv set:

$ greetings
#!/bin/sh -xv
#
# Time of day greetings
#
hour=`date +%H`
+ date +%H
hour=11

if [ $hour -le 12 ]
then
        echo "Good Morning!"
elif [ $hour -le 17 ]
then
        echo "Good Afternoon!"
else
        echo "Good Night!"
fi
+ [ 11 -le 12 ]
+ echo Good Morning!
Good Morning!
$

Understanding Shell Parsing Order

Each shell analyzes commands, whether from the command line or in a script, and then parses them (divides them up) into recognizable parts. Shells can perform many kinds of substitutions and expansions. These operations are carried out in a very specific order for each shell. The parsing order for a shell can have a definite impact on shell programs that you write. Understanding the parsing order can help you determine where a script may be broken. Figure 16-2 shows a simplified version of Korn shell parsing order. When a command or string is quoted, the parsing order is affected. It can be difficult to understand exactly how the evaluation process works. Nevertheless, sometimes understanding the order in which a shell performs its operation can provide some insight into a problem. The Bourne shell parses in a similar order to the Korn shell, omitting history and alias substitution.


Figure 16-2  Korn shell parsing order.

Figure 16-3 shows a simplified version of C shell parsing order.


Figure 16-3  C shell parsing order.

The Bourne shell script that follows fails because variable expansion occurs after redirection:

$ moreit='| more'
$ cat   /etc/passwd $moreit
ppp:x:12881:1:PPP:/tmp:/usr/etc/ppp-listen
root:x.:Ø:1:Operator:/:/bin/csh
nobody:x:65534:65534::/:
(Lines omitted from example)
+::Ø:Ø:::
cat: |: No such file or directory
cat: more: No such file or directory

See Chapter 17 for shell programming reference tables and for examples of more complex shell scripts.


Previous Table of Contents Next