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.$$
Copyright © 2003 O'Reilly & Associates. All rights reserved.