XXX Chapter 24. Functions¶
Table of Contents
24.1. Complex Functions and Function Complexities
24.2. Local Variables
24.3. Recursion Without Local Variables
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. Wherever there is repetitive code, when a task repeats with only slight variations in procedure, then consider using a function.
- function `` function_name `` {
- `` command `` ... }
or `` function_name `` () {
`` command `` ... }
This second form will cheer the hearts of C programmers (and is more portable ).
As in C, the function’s opening bracket may optionally appear on the second line.
- `` function_name `` ()
- { `` command `` ... }
|Note
A function may be “compacted” into a single line.
fun () { echo "This
- is a function”; echo; }
- #
- ^ ^
In this case, however, a semicolon must follow the final command in the function.
fun () { echo "This
- is a function”; echo } #
- Error!
- #
- ^
fun2 () { echo “Even
a single-command functi
- on? Yes!”; }
#
^
fun () { echo "This is a function"; echo; }
# ^ ^
fun () { echo "This is a function"; echo } # Error!
# ^
fun2 () { echo "Even a single-command function? Yes!"; }
# ^
fun () { echo "This is a function"; echo; }
# ^ ^
fun () { echo "This is a function"; echo } # Error!
# ^
fun2 () { echo "Even a single-command function? Yes!"; }
# ^
Functions are called, triggered , simply by invoking their names. A function call is equivalent to a command.
Exemple 1. Simple functions¶
#!/bin/bash
# ex59.sh: Exercising functions (simple).
JUST_A_SECOND=1
funky ()
{ # This is about as simple as functions get.
echo "This is a funky function."
echo "Now exiting funky function."
} # Function declaration must precede call.
fun ()
{ # A somewhat more complex function.
i=0
REPEATS=30
echo
echo "And now the fun really begins."
echo
sleep $JUST_A_SECOND # Hey, wait a second!
while [ $i -lt $REPEATS ]
do
echo "----------FUNCTIONS---------->"
echo "<------------ARE-------------"
echo "<------------FUN------------>"
echo
let "i+=1"
done
}
# Now, call the functions.
funky
fun
exit $?
The function definition must precede the first call to it. There is no method of “declaring” the function, as, for example, in C.
f1
# Will give an error message, since function "f1" not yet defined.
declare -f f1 # This doesn't help either.
f1 # Still an error message.
# However...
f1 ()
{
echo "Calling function \"f2\" from within function \"f1\"."
f2
}
f2 ()
{
echo "Function \"f2\"."
}
f1 # Function "f2" is not actually called until this point,
#+ although it is referenced before its definition.
# This is permissible.
# Thanks, S.C.
|Note
Functions may not be empty!
#!/bin/bash
# empty-function.sh
empty ()
{
}
exit 0 # Will not e
xit here!
# $ sh empty-functio
- n.sh
- # empty-function.sh:
line 6: syntax error ne
- ar unexpected token `}’
- # empty-function.sh:
line 6: `}’
# $ echo $? # 2
# Note that a functi
on containing only comme nts is empty.
func () {
# Comment 1. # Comment 2. # This is still an
- empty function.
- # Thank you, Mark
Bova, for pointing this out.
} # Results in same er
ror message as above.
# However ...
not_quite_empty () {
illegal_command} # A script contai
ning this function will not bomb
#+ as long as the
function is not called.
not_empty () {
:} # Contains a : (nu
- ll command), and this is
okay.
# Thank you, Dominic
k Geyer and Thiemo Kelln er.
#!/bin/bash
# empty-function.sh
empty ()
{
}
exit 0 # Will not exit here!
# $ sh empty-function.sh
# empty-function.sh: line 6: syntax error near unexpected token `}'
# empty-function.sh: line 6: `}'
# $ echo $?
# 2
# Note that a function containing only comments is empty.
func ()
{
# Comment 1.
# Comment 2.
# This is still an empty function.
# Thank you, Mark Bova, for pointing this out.
}
# Results in same error message as above.
# However ...
not_quite_empty ()
{
illegal_command
} # A script containing this function will *not* bomb
#+ as long as the function is not called.
not_empty ()
{
:
} # Contains a : (null command), and this is okay.
# Thank you, Dominick Geyer and Thiemo Kellner.
#!/bin/bash
# empty-function.sh
empty ()
{
}
exit 0 # Will not exit here!
# $ sh empty-function.sh
# empty-function.sh: line 6: syntax error near unexpected token `}'
# empty-function.sh: line 6: `}'
# $ echo $?
# 2
# Note that a function containing only comments is empty.
func ()
{
# Comment 1.
# Comment 2.
# This is still an empty function.
# Thank you, Mark Bova, for pointing this out.
}
# Results in same error message as above.
# However ...
not_quite_empty ()
{
illegal_command
} # A script containing this function will *not* bomb
#+ as long as the function is not called.
not_empty ()
{
:
} # Contains a : (null command), and this is okay.
# Thank you, Dominick Geyer and Thiemo Kellner.
It is even possible to nest a function within another function, although this is not very useful.
f1 ()
{
f2 () # nested
{
echo "Function \"f2\", inside \"f1\"."
}
}
f2 # Gives an error message.
# Even a preceding "declare -f f2" wouldn't help.
echo
f1 # Does nothing, since calling "f1" does not automatically call "f2".
f2 # Now, it's all right to call "f2",
#+ since its definition has been made visible by calling "f1".
# Thanks, S.C.
Function declarations can appear in unlikely places, even where a command would otherwise go.
ls -lfoo() { echo "foo"; } # Permissible, but useless.
if [ "$USER" = bozo ]
then
bozo_greet () # Function definition embedded in an if/then construct.
{
echo "Hello, Bozo."
}
fi
bozo_greet # Works only for Bozo, and other users get an error.
# Something like this might be useful in some contexts.
NO_EXIT=1 # Will enable function definition below.
[[ $NO_EXIT -eq 1 ]] && exit() { true; } # Function definition in an "and-list".
# If $NO_EXIT is 1, declares "exit ()".
# This disables the "exit" builtin by aliasing it to "true".
exit # Invokes "exit ()" function, not "exit" builtin.
# Or, similarly:
filename=file1
[ -f "$filename" ] &&
foo () { rm -f "$filename"; echo "File "$filename" deleted."; } |
foo () { echo "File "$filename" not found."; touch bar; }
foo
# Thanks, S.C. and Christopher Head
Function names can take strange forms.
_(){ for i in {1..10}; do echo -n "$FUNCNAME"; done; echo; }
# ^^^ No space between function name and parentheses.
# This doesn't always work. Why not?
# Now, let's invoke the function.
_ # __________
# ^^^^^^^^^^ 10 underscores (10 x function name)!
# A "naked" underscore is an acceptable function name.
# In fact, a colon is likewise an acceptable function name.
:(){ echo ":"; }; :
# Of what use is this?
# It's a devious way to obfuscate the code in a script.
See also Example A-56
|Note
What happens when different versions of the same function appear in a script?
# As Yan Chen point
- s out,
- # when a function i
s defined multiple times ,
# the final version
- is what is invoked.
- # This is not, howe
ver, particularly useful .
func () {
echo “First versio
- n of func ().”
}
func () {
echo “Second versi- on of func ().”
}
func # Second vers
ion of func ().
exit $?
# It is even possib
le to use functions to o verride
#+ or preempt system
- commands.
- # Of course, this i
s not advisable.
# As Yan Chen points out,
# when a function is defined multiple times,
# the final version is what is invoked.
# This is not, however, particularly useful.
func ()
{
echo "First version of func ()."
}
func ()
{
echo "Second version of func ()."
}
func # Second version of func ().
exit $?
# It is even possible to use functions to override
#+ or preempt system commands.
# Of course, this is *not* advisable.
# As Yan Chen points out,
# when a function is defined multiple times,
# the final version is what is invoked.
# This is not, however, particularly useful.
func ()
{
echo "First version of func ()."
}
func ()
{
echo "Second version of func ()."
}
func # Second version of func ().
exit $?
# It is even possible to use functions to override
#+ or preempt system commands.
# Of course, this is *not* advisable.