Previous Section  < Day Day Up >  Next Section

12.8. Functions

Korn shell functions are similar to those used in the Bourne shell, and are used to modularize your program. A function is a collection of one or more commands that can be executed simply by entering the function's name, similar to a built-in command. Here is a review of some of the important rules about using functions.

  1. The Korn shell executes built-in commands first, then functions, and then executables. Functions are read into memory once when they are defined, not every time they are referenced.

  2. A function must be defined before it is used; therefore, it is best to place function definitions at the beginning of the script.

  3. The function runs in the current environment; it shares variables with the script that invoked it, and lets you pass arguments by setting them as positional parameters. The present working directory is that of the calling script. If you change the directory in the function, it will be changed in the calling script.

  4. In the Korn shell, you can declare local variables in the function using the typeset command. Ksh functions can be exported to subshells.

  5. The return statement returns the exit status of the last command executed within the function or the value of the argument given, and cannot exceed a value of 255.

  6. To list functions and definitions, use the preset alias, functions.

  7. Traps are local to functions and will be reset to their previous value when the function exits (not so with the Bourne shell).

  8. Functions can be recursive, that is, call themselves. Recursion should be handled carefully. The Korn shell will warn you otherwise with the message, recursion too deep.

  9. Functions can be autoloaded; they are defined only if referenced. If never referenced, they are not loaded into memory.

  10. Versions of the Korn shell that are more recent than 1988 also support discipline functions, passing variables by reference, and compound variables. A built-in command is no longer found before a function of the same name. In older versions it was necessary to use a combination of aliases and functions to write a function that would override a built-in command.[3]

    [3] David G. Korn and Morris I. Bolsky, The Korn Shell Command and Programming Language (Englewood Cliffs, NJ: Prentice-Hall, Inc., 1988), p. 77.

12.8.1 Defining Functions

A function must be defined before it can be invoked. Korn shell functions are defined with the keyword function preceding the function name. The curly braces must have a space on the inside of each brace. (Please see "Functions" on page 372 for the older-style Bourne shell function definition; these are still compatible in Korn shell scripts.)

FORMAT


function function_name { commands; commands; }


Example 12.53.

function usage { print "Usage $0 [-y] [-g] " ; exit 1; }


EXPLANATION

The function name is usage. It is used to print a diagnostic message and exit the script if the script does not receive the proper arguments, either –y or –g.

12.8.2 Listing and Unsetting Functions

To list local function definitions, type typeset –f. To list exported function definitions, type typeset –fx. To unset a function, type unset –f function_name. See the typeset command, Table 12.11 on page 714.

Table 12.11. typeset and Function Options

Option

What It Does

typeset –f

Displays all functions and their values. Must have a history file, as all function definitions are stored there.

typeset +f

Displays just function names.

typeset –fx

Displays all function definitions that will be exported across shell scripts, but not as a separate invocation of ksh.

typeset –fu func

func is the name of a function that has not yet been defined.


12.8.3 Local Variables and the Return Value

The typeset command can be used to create local variables. These variables will be known only in the function where they are created. Once out of the function, the local variables are undefined.

The return value of a function is really just the value of the exit status of the last command in the script unless a specific return command is used. If a value is assigned to the return command, that value is stored in the ? variable. It can hold an integer value between 0 and 255. Because the return command is limited to returning only integer values, you can use command substitution to return the output of a function and assign the output to a variable, just as you would if getting the output of a UNIX command.

Example 12.54.

(The Script)

     #!/bin/ksh

     # Scriptname: do_increment

     # Using the return Command)





(The Output)

     $ do_increment

5    The sum is 6

     6


EXPLANATION

  1. The function called increment is defined.

  2. The typeset command defines the variable sum to be local to this function.

  3. The return built-in command, when given an argument, returns to the main script after the line where the function was invoked and stores its argument in the ? variable. In the script, the increment function is called with an argument.

  4. The increment function is called with an argument of 5.

  5. The exit status of the function is stored in ? unless an explicit argument is given to the return command. The return command argument specifies a return status for the function, its value is stored in the ? variable, and it must be an integer between 0 and 255.

  6. Because sum was defined as a local variable in the function increment, it is not defined in the script that invoked the function. Nothing is printed.

Example 12.55.

(Using Command Substitution)

(The Script)

     # Scriptname: do_square

     #!/bin/ksh

1    function square {

      (( sq = $1 * $1 ))

         print "Number to be squared is $1."

2        print "The result is $sq "

     }

3    read number?"Give me a number to square. "

4    value_returned=$(square $number)

5    print $value_returned



(The Output)

     $ do_square

5    Number to be squared is 10. The result is 100


EXPLANATION

  1. The function called square is defined. It will multiply its argument times itself.

  2. The result of squaring the number is printed.

  3. The user is asked for input.

  4. The function square is called with a number (input from the user) as its argument. Command substitution is performed because the function is enclosed in parentheses preceded by a $. The output of the function (both of its print statements) is assigned to the variable value_returned.

  5. The command substitution removes the newline between the strings Number to be squared is and The result is 100.

12.8.4 Exported Functions

Function definitions are not inherited by subshells unless you define them in the ENV file with the typeset command, for example, typeset –fx function_names.

You can export functions with typeset –fx from the current Korn shell to a script, or from one script to another, but not from one invocation of ksh to the next (e.g., a separate invocation means that if you type ksh at the prompt, a brand new shell is started up). Exported function definitions will not be inherited by the new shell.

Example 12.56.

(The First Script)

     $ cat calling_script

     #!/bin/ksh

1    function sayit { print "How are ya $1?" ; }

2    typeset –fx sayit   # Export sayit to other scripts

3    sayit Tommy

4    print "Going to other script"

5    other_script        # Call other_script

     print "Back in calling script"

****************************************************************

(The Second Script)

     $ cat other_script   # NOTE: This script cannot be invoked with #!/bin/ksh

6    print "In other script "

7    sayit Dan

8    print "Returning to calling script"



(The Output)

     $ calling_script

3    How are ya Tommy?

4    Going to other script

6    In other script

7    How are ya Dan?

8    Returning to calling script

     Back in calling script


EXPLANATION

  1. The function sayit is defined. It will accept one argument to be stored in $1.

  2. The typeset command with the –fx option allows the function to be exported to any script called from this script.

  3. The function sayit is invoked with Tommy as an argument. Tommy will be stored in $1 in the function.

  4. After the sayit function terminates, the program resumes here.

  5. The script, called other_script, is executed.

  6. We are now in the other script. This script is called from the first script, sayit. It cannot start with the line #!/bin/ksh because this line causes a ksh subshell to be started, and exporting functions does not work if a separate Korn shell is invoked.

  7. The function sayit is invoked. Dan is passed as an argument, which will be stored in $1 in the function.

  8. After this line is printed, other_script terminates and control goes back to the calling script at the line where it left off after the function was invoked.

12.8.5 Function Options and the typeset Command

The typeset command is used to display function attributes. See Table 12.11.

Autoloaded Functions

An autoloaded function is not loaded into your program until you reference it. The autoloaded function can be defined in a file somewhere else and the definition will not appear in your script, allowing you to keep the script small and compact. To use autoload, you need to set the FPATH variable in your ENV file. The FPATH variable contains a search path for directories containing function files. The files in this directory have the same names as the functions defined within them.

The autoload alias for typeset –fu specifies that the function names that have not yet been defined are to be autoloaded functions. After the autoload command is executed with the function as its argument, you must invoke the function to execute the commands contained in it. The primary advantage of autoloading functions is better performance, because the Korn shell does not have to read the function definition if it has never been referenced.[4]

[4] Morris I. Bolsky and David G. Korn, The New Kornshell (Upper Saddle River, NJ: Prentice Hall, 1995), p. 78.

Example 12.57.

(The Command Line)

1    $ mkdir functionlibrary

2    $ cd functionlibrary

3    $ vi foobar



(In Editor)

4    function foobar { pwd; ls; whoami; }  # function has the same name as the file.



(In .profile File)

5   export FPATH=$HOME/functionlibrary    # This path is searched for functions.

(In Your Script)

6   autoload foobar

7   foobar


EXPLANATION

  1. Make a directory in which to store functions.

  2. Go to the directory.

  3. foobar is a file in functionlibrary. The file foobar contains the definition of function foobar. The filename and function name must match.

  4. The function foobar is defined in the file called foobar.

  5. In the user's .profile initialization file, the FPATH variable is assigned the path where the functions are stored. This is the path the Korn shell will search when autoloading a function. FPATH is exported.

  6. In your script, the function foobar is brought into the program's memory.

  7. The function foobar is invoked.

A number of functions can be stored in one file; for example, calculation functions may be contained in a file called math. Because the function must have the same name as the file in which it is stored, you may create hard links to the function file. Each function name will be a link to the file in which the function is defined. For example, if a function in the math file is called square, use the UNIX/Linux ln command to give the math file another name, square. Now the math file and square file can be referenced, and in either case you are referencing the file by the corresponding function name. Now the square function can be autoloaded by its own name.

Example 12.58.

(The Command Line)

1    $ ln math square add divide

2    $ ls -i

     12256 add

     12256 math

     12256 square

     12256 divide

3    $ autoload square; square


EXPLANATION

  1. The UNIX/Linux ln (link) command lets you give a file alternate names; math and square are the same file. The link count is incremented by one for each link created.

  2. A listing shows that all files have the same inode number, meaning they are all one file but can be accessed with different names.

  3. Now, when the square file is autoloaded, the function square has the same name and will be invoked. None of the other functions defined in the file can be referenced until they, in turn, have been specifically autoloaded by name.

    Previous Section  < Day Day Up >  Next Section