3.19. Functions

Like "real" programming languages, bash has functions, though in a somewhat limited implementation. A function is a subroutine, a code block that implements a set of operations, a "black box" that performs a specified task. Whenever there is repetitive code, when a task repeats with only slight variations, then writing a function should be investigated.

function function-name {
command...
}

or

function-name () {
command...
}

This second form will cheer the hearts of C programmers.

The opening bracket in the function may optionally be placed on the second line, to more nearly resemble C function syntax.

function-name ()
{
command...
}

Functions are called, triggered, simply by invoking their names.

Note that the function definition must precede the first call to it. There is no method of "declaring" the function, as, for example, in C.


Example 3-80. Simple function

   1 #!/bin/bash
   2 
   3 funky ()
   4 {
   5   echo This is a funky function.
   6   echo Now exiting funky function.
   7 }
   8 
   9 # Note: function must precede call.
  10 
  11 # Now, call the function.
  12 
  13 funky
  14 
  15 exit 0

More complex functions may have arguments passed to them and return exit values to the script for further processing.

   1 function-name $arg1 $arg2

The function refers to the passed arguments by position (as if they were positional parameters), that is, $1, $2, and so forth.


Example 3-81. Function Taking Parameters

   1 #!/bin/bash
   2 
   3 func2 () {
   4    if [ -z $1 ]
   5    # Checks if any params.
   6    then
   7      echo "No parameters passed to function."
   8      return 0
   9    else
  10      echo "Param #1 is $1."
  11    fi
  12 
  13    if [ $2 ]
  14    then
  15      echo "Parameter #2 is $2."
  16    fi
  17 }
  18    
  19 func2
  20 # Called with no params
  21 echo
  22 
  23 func2 first
  24 # Called with one param
  25 echo
  26 
  27 func2 first second
  28 # Called with two params
  29 echo
  30 
  31 exit 0

Note

In contrast to certain other programming languages, shell scripts permit passing only value parameters to functions. Variable names (which are actually pointers), if passed as parameters to functions, will be treated as string literals and cannot be dereferenced. Functions interpret their arguments literally.

exit status

Functions return a value, called an exit status. The exit status may be explicitly specified by a return statement, otherwise it is the exit status of the last command in the function (0 if successful, and a non-zero error code if not). This exit status may be used in the script by referencing it as $?.

return

Terminates a function. The return statement optionally takes an integer argument, which is returned to the calling script as the "exit status" of the function, and this exit status is assigned to the variable $?.


Example 3-82. Converting numbers to Roman numerals

   1 #!/bin/bash
   2 
   3 # Arabic number to Roman numeral conversion
   4 # Range 0 - 200
   5 # It's crude, but it works.
   6 
   7 # Extending the range and otherwise improving the script
   8 # is left as an exercise for the reader.
   9 
  10 # Usage: roman number-to-convert
  11 
  12 ARG_ERR=1
  13 OUT_OF_RANGE=200
  14 
  15 if [ -z $1 ]
  16 then
  17   echo "Usage: `basename $0` number-to-convert"
  18   exit $ARG_ERR
  19 fi  
  20 
  21 num=$1
  22 if [ $num -gt $OUT_OF_RANGE ]
  23 then
  24   echo "Out of range!"
  25   exit $OUT_OF_RANGE
  26 fi  
  27 
  28 to_roman ()
  29 {
  30 number=$1
  31 factor=$2
  32 rchar=$3
  33 let "remainder = number - factor"
  34 while [ $remainder -ge 0 ]
  35 do
  36   echo -n $rchar
  37   let "number -= factor"
  38   let "remainder = number - factor"
  39 done  
  40 
  41 return $number
  42 }
  43 
  44 # Note: must declare function
  45 #       before first call to it.
  46 
  47 to_roman $num 100 C
  48 num=$?
  49 to_roman $num 90 LXXXX
  50 num=$?
  51 to_roman $num 50 L
  52 num=$?
  53 to_roman $num 40 XL
  54 num=$?
  55 to_roman $num 10 X
  56 num=$?
  57 to_roman $num 9 IX
  58 num=$?
  59 to_roman $num 5 V
  60 num=$?
  61 to_roman $num 4 IV
  62 num=$?
  63 to_roman $num 1 I
  64 
  65 echo
  66 
  67 exit 0

local variables

A variable declared as local is one that is visible only within the block of code in which it appears. In a shell script, this means the variable has meaning only within its own function.


Example 3-83. Local variable visibility

   1 #!/bin/bash
   2 
   3 func ()
   4 {
   5   local a=23
   6   echo
   7   echo "a in function is $a"
   8   echo
   9 }  
  10 
  11 func
  12 
  13 # Now, see if local 'a'
  14 # exists outside function.
  15 
  16 echo "a outside function is $a"
  17 echo
  18 # Nope, 'a' not visible globally.
  19 
  20 exit 0

Local variables permit recursion (a recursive function is one that calls itself), but this practice usually involves much computational overhead and is definitely not recommended in a shell script.


Example 3-84. Recursion, using a local variable

   1 #!/bin/bash
   2 
   3 #               factorial
   4 #               ---------
   5 
   6 
   7 # Does bash permit recursion?
   8 # Well, yes, but...
   9 # You gotta have rocks in your head to try it.
  10 
  11 
  12 MAX_ARG=5
  13 WRONG_ARGS=1
  14 RANGE_ERR=2
  15 
  16 
  17 if [ -z $1 ]
  18 then
  19   echo "Usage: `basename $0` number"
  20   exit $WRONG_ARGS
  21 fi
  22 
  23 if [ $1 -gt $MAX_ARG ]
  24 then
  25   echo "Out of range (5 is maximum)."
  26   # Let's get real now...
  27   # If you want greater range than this, rewrite it in a real programming language.
  28   exit $RANGE_ERR
  29 fi  
  30 
  31 fact ()
  32 {
  33   local number=$1
  34   # Variable "number" must be declared as local otherwise this doesn't work.
  35   if [ $number -eq 0 ]
  36   then
  37     factorial=1
  38   else
  39     let "decrnum = number - 1"
  40     fact $decrnum  # Recursive function call.
  41     let "factorial = $number * $?"
  42   fi
  43 
  44   return $factorial
  45 }
  46 
  47 fact $1
  48 echo "Factorial of $1 is $?."
  49 
  50 exit 0