home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Unix Power ToolsUnix Power ToolsSearch this book

35.30. Using Shell Functions in Shell Scripts

So far, we have discussed some shell function basics (Section 29.11), using examples such as the mx( ) function that uses sed and dig to find out what host accepts mail for a given address. In that example, we simply made a set of complex functionality available as a quick and easy (and short) call from the command line. But you can also define functions and use them within shell scripts, or you can use the . and source commands to include those functions from an external file (Section 35.29).

We've also discussed using functions to automate repetitive tasks (Section 29.11), such as calculating factorials.

For now, let's demonstrate both of these approaches specifically with respect to defining a function to automate a repetitive task and then sharing the function with other shell scripts. Using the mx( ) function we defined earlier, let's put it into its own file, mx.sh, and store it in our personal shell function library directory (in this case, $HOME/lib):

$ cat > ~/lib/mx.sh
function mx( ) {
# Look up mail exchanger for host(s)
for host
do
    echo "==== $host ===="
    dig "$host" mx in |
    sed -n '/^;; ANSWER SECTION:/,/^$/{
            s/^[^;].* //p
    }'
done
}
^D
$ more !$
function mx( ) {
# Look up mail exchanger for host(s)
for host
do
    echo "==== $host ===="
    dig "$host" mx in |
    sed -n '/^;; ANSWER SECTION:/,/^$/{
            s/^[^;].* //p
    }'
done
}
$

Now the file ~/lib/mx.sh contains a function named mx( ) -- fair enough, but let's say we want to be able to pass a list of hosts (determined dynamically on a regular basis, say, from spam-fighting tools that find open SMTP proxies) to a shell script, and have that shell script email a form letter to the postmaster address at that host. We will call the shell script proxynotify, and call it as follows:

$ proxynotify < proxyList

proxylist contains a list of hosts, one per line, in the com domain. We want to iterate over them and mail the postmaster for the domain, rather than mailing directly to an address such as postmaster@[IP], on the assumption that maybe the top-level postmaster can fix what may be an unmonitored relay. Just to verify that some other system isn't responsible for delivering the mail, we will check using the mx( ) shell function. We've also included a quickie shell function named ip( ) that returns the IP address for a given hostname. As you can see, we use a local variable for the IP address, and we use the -z test for zero length of a string. We also check whether the file is readable, check the script arguments, and use a variety of other tricks.

#!/bin/sh
# proxynotify demo

# get our function
. $HOME/lib/mx.sh

function ip( ) {
    for host
    do
        local ip=`dig in host $host |\
        grep $host |\
        grep "TABATAB" |\
        awk '{print $5}'`
        echo $ip
    done
}

if [ -z "$1" ]
then
    echo "Usage: $0 [file]"
    exit 1
elif [ -r "$1" ]
then
    echo "found a file and it is readable"
else
    echo "file $1 not readable or does not exist"
    exit 1
fi

    for domain in `cat "$1"`
    do
    echo "processing $domain"
    themx=`mx $domain`
    echo "MX for $domain is '$themx'"
    if [ ! -z $themx ]
    then
        cat formletter | mail -s "proxy" postmaster@$themx
    else
        echo "couldn't find MX for $domain,"
        echo "mailing direct-to-IP instead."
        theip=`ip $domain`
        if [ ! -z $theip ]; then
            cat formletter | mail -s "proxy" postmaster@$theip
        else
            echo "giving up, can't find anyone to notify"
            echo "$domain" >> /tmp/proxybadlist.$$
            return 1
        fi
   fi
done
mail -s "bad proxies" <</tmp/proxybadlist.$$
rm /tmp/proxybadlist.$$

-- SJC



Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.