Articles‎ > ‎

Shell scripting 101: Part 4

posted Dec 19, 2008, 5:46 AM by Philip Rinehart   [ updated Dec 19, 2008, 5:47 AM by Greg Neagle ]
In the previous three parts of this series, we've looked at how to write a basic shell script.  It's now time to get more in depth on the subject, and examine more advanced shell script syntax.  Let's start with functions.

Functions 

Exactly what is a function?  It is a piece of shell script code which performs a well defined task.  Think of it as a small piece of shell script which can be used multiple times either in a script, or in multiple scripts.  One very important consideration about variables in functions.  They are shared.  If the function calls the same variable as its parent script, it will reset the value.  Let's look at a very simple example:

my_function () 
{
echo "testing my function"
}

 Looks pretty straightforward, right?  It is for the most part.   Note the function name on the first line, my_function.  What are the parentheses used for?  Not much, and they can be omitted, but it is considered best practice to include them.  Great, so that's a simple function, but it isn't really that useful.  Functions return an exit value, which can be used.  In most cases, when writing scripts, passing a value to the function is accomplished by simply passing the value with an argument.

  More complex uses of functions

Exit values from functions are returned with the use of the return command.  Using an abbreviated example from the Advanced Bash Shell Scripting Guide.

#!/bin/bash

return_test ()         # Returns whatever passed to it.
{
  return $1
}
return_test 27         # o.k.echo $?                # Returns 27.
exit 0

Let's look at how this script calls a function.  In this case the function being used return_test, returns the exit value immediately.  Also note how the function is invoked in the shell script.  Use the name of the function, followed by any number of arguments to the function.  Simple enough, right?  Yes, but often the reason functions are written is so that they can be used across a wide variety of shell scripts.  In other programming languages, these are referred to as function libraries.

Function libraries

Function libraries are commonly used on OS X all the time.  In fact, a function library is used each and every time a machine boots up!  How?  Startup Items on OS X are simple shell scripts.  Let's use the NetworkTime startup item as an instructive example:

. /etc/rc.common
StartService ()
{
if [ "${TIMESYNC:=-YES-}" = "-YES-" ] &&
! GetPID ntpd > /dev/null; then
CheckForNetwork
if [ -f /var/run/NetworkTime.StartupItem -o "${NETWORKUP}" = "-NO-" ]; then exit; fi
touch /var/run/NetworkTime.StartupItem
echo "Starting network time synchronization"
# Synchronize our clock to the network's time,
# then fire off ntpd to keep the clock in sync.
ntpdate -bvs
ntpd -f /var/run/ntp.drift -p /var/run/ntpd.pid
fi
}

 Look at this snippet.  What is the . /etc/rc.common line for?  It is called "sourcing" a function and is how functions from libraries of shell scripts are called.  Looking at the StartService function above, CheckForNetwork is not a function defined in this shell script.  It is actually being used from the rc.common function library. 

Command substitution

Command substitution is how bash uses the output, STDOUT, of a command and then assigns it to a variable.  Here is an example.

script=`basename $0`
echo $script

 Note the use of backticks.  The script variable is assigned the value of the command basename $0.  Sure, but bash now can use a more readable version of command substitution, using the $ and parentheses.  Taking the above example using the $ and parentheses syntax:

script=$(basename $0)
echo $script

This has the benefit of not trying to control single and double quoting, which can become quite complex in a shell script.  It also makes the script more readable. 

Now that functions and command substitution aren't a mystery, open /etc/rc.common in a text editor.  Take a close look at the CheckForNetwork function, and the GetPID function.  This script nicely exhibits the use of tests, functions, command line substitutions, basically everything that this series has examined up until now. Next time, we'll talk about some of the internal built-in commands for bash, and how they can be leveraged.

Comments