Shell functions

Like C programs, Shell scripts can be broken up into functions, which is more efficient than having multiple scripts calling each other (however, it does mean the function cannot be shared by different scripts).

e.g. A program to calculate how much space your web pages take up, as a percent of your total file space. Defines 2 functions, then uses them:


# percent $1 $2
# returns $1 as a percentage of $2

percent()
{
 temp=`expr $1 \* 100`
 expr $temp / $2
}


# sizeof dir
# returns size of all files in dir and below

sizeof()
{
 cd $1
 du | grep '\.$' | cut -f1 
}


web=`sizeof $HOME/public_html`
echo $web

total=`sizeof $HOME`
echo $total

ans=`percent $web $total`
echo "Your web files are $ans% of your total files."




Environment Variables

By default, functions have access to the caller's environment variables without exporting:

fn()
{
 echo $x
}

x=3

fn
Whereas if we call a separate script, it does not by default have access to the caller's environment variables.




Piping to a function:

You can pipe to functions too (in general you can treat them just like a separate program).

Consider a program:


#  killstring (string)
# kills all instances of program named by string
# e.g. 
#  killstring textedit
# kills all your textedit processes

If "killstring" first tries to identify these processes:
  ps -fu $USER | grep -i $1
when you type "killstring textedit" you get something like:
humphrys 28414 28413  0 12:32:50 pts/5    0:00 grep -i textedit
humphrys 28396     1  0 12:32:19 pts/23   0:00 textedit -geometry 600x600+200-100 f1
humphrys 28352     1  0 12:31:51 pts/23   0:00 textedit -geometry 600x600+200-100 f2
humphrys 28366     1  0 12:31:51 pts/23   0:00 textedit -geometry 600x600+200-100 f3
humphrys 28413 28073  0 12:32:50 pts/5    0:00 /bin/sh killstring textedit
so we need to strip out killstring itself, and the grep itself. We also have a number of unwieldy lines of text, which we want to process 1 by 1, to extract the process ID and kill it. We can do this by piping to a function. So killstring looks like:

fn()
{
 while read user pid restofline
 do
  kill $pid
 done
}


ps -fu $USER | grep -i $1 | grep -v $0 | grep -v "grep -i $1" | fn