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.$$