Prev (External Programs) | Next (Hints And Tips) |
. ./library.shgoes at the start of the script.
There could be some confusion about whether to call shell functions procedures or functions; the definition of a function is traditionally that is returns a single value, and does not output anything. A procedure, on the other hand, does not return a value, but may produce output. A shell function may do neither, either or both. It is generally accepted that in shell scripts they are called functions.
A function may return a value in three ways:
exit
command to end the shell scriptreturn
command to end the function, and return the supplied value to the calling section
of the shell scriptexit
stops the program, and return
returns
control to the caller. The difference is that a shell function cannot change its parameters, though
it can change global parameters.
A simple script using a function would look like this:
#!/bin/sh # A simple script with a function... add_a_user() { USER=$1 PASSWORD=$2 shift; shift; # Having shifted twice, the rest is now comments ... COMMENTS=$@ echo "Adding user $USER ..." echo useradd -c "$COMMENTS" $USER echo passwd $USER $PASSWORD echo "Added user $USER ($COMMENTS) with password $PASSWORD" } ### # Main body of script starts here ### echo "Start of script..." add_a_user bob letmein Bob Holness the presenter add_a_user fred badpassword Fred Durst the singer add_a_user bilko worsepassword Sgt. Bilko the role model echo "End of script..."
{
, and everything following to the
matching }
is taken to be the code of that function.
Note that for this example the useradd
and passwd
commands have been prefixed with echo
- this is a useful
debugging technique to check that the right commands would be executed.
It also means that you can run the script without being root or adding
dodgy user accounts to your system!
We have been used to the idea that a shell
script is executed sequentially. This is not so with functions.
In this case, the function add_a_user
is read in and checked for syntax,
but not executed until it is explicitly called.
Execution starts with the echo
statement "Start of script...". The next line, add_a_user bob letmein Bob Holness
is
recognised as a function call so the add_a_user
function is entered
and starts executing with certain additions to the environment:
$1=bob $2=letmein $3=Bob $4=Holness $5=the $6=presenterSo within that function,
$1
is set to bob
,
regardless of what $1
may be set to outside of the function.
A=$1
before we call the function.
Then, within the function, we can refer to $A
.
shift
command again to get the $3
and
onwards parameters into $@
.
The function then adds the user and sets their password. It echo
es
a comment to that effect, and returns control to the next line of the main
code.
$1
, $2
, $@
, etc).#!/bin/sh myfunc() { echo "I was called as : $@" x=2 } ### Main script starts here echo "Script was called with $@" x=1 echo "x is $x" myfunc 1 2 3 echo "x is $x"
scope.sh a b c
, gives the following output:
Script was called with a b c x is 1 I was called as : 1 2 3 x is 2
$@
parameters are changed within the function to reflect
how the function was called. The variable x
, however, is
effectively a global variable - myfunc
changed it, and that
change is still effective when control returns to the main script.
Functions cannot change the values they have been called with, either - this
must be done by changing the variables themselves, not the parameters
as passed to the script.
An example shows this more clearly:
#!/bin/sh myfunc() { echo "\$1 is $1" echo "\$2 is $2" # cannot change $1 - we'd have to say: # 1="Goodbye Cruel" # which is not a valid syntax. However, we can # change $a: a="Goodbye Cruel" } ### Main script starts here a=Hello b=World myfunc $a $b echo "a is $a" echo "b is $b"
#!/bin/sh factorial() { if [ "$1" -gt "1" ]; then i=`expr $1 - 1` j=`factorial $i` k=`expr $1 \* $j` echo $k else echo 1 fi } while : do echo "Enter a number:" read x factorial $x done
# common.lib # Note no #!/bin/sh as this should not spawn an extra shell. # It's not the end of the world to have one, but clearer not to. # STD_MSG="About to rename some files..." rename() { # expects to be called as: rename .txt .bak FROM=$1 TO=$2 for i in *$FROM do j=`basename $i $FROM` mv $i ${j}$TO done }
#!/bin/sh # function2.sh . ./common.lib echo $STD_MSG rename txt bak
#!/bin/sh # function3.sh . ./common.lib echo $STD_MSG rename html html-bak
function2.sh
and
function3.sh
, each sourceing the common library
file common.lib
, and using variables and functions declared
in that file.
return
call.
#!/bin/sh adduser() { USER=$1 PASSWD=$1 shift ; shift COMMENTS=$@ useradd -c "${COMMENTS}" $USER if [ "$?" -ne "0" ]; then echo "Useradd failed" return 1 fi passwd $USER $PASSWD if [ "$?" -ne "0" ]; then echo "Setting password failed" return 2 fi echo "Added user $USER ($COMMENTS) with password $PASSWORD" } ## Main script starts here adduser bob letmein Bob Holness, the famous BlockBusters presenter! if [ "$?" -eq "1" ]; then echo "Something went wrong with useradd" else if [ "$?" -eq "2" ]; then echo "Something went wrong with passwd" fi else echo "Bob Holness added to the system." fi
useradd
and passwd
), and lets the user
know if they fail. The function then defines a return code of 1 to indicate any problem with useradd
, and 2 to
indicate any problem with passwd
. That way, the calling script knows where the problem lay.
Prev (External Programs) | Next (Hints And Tips) |