Unix: Scripting with templates

One of the best ways to write scripts quickly and effectively is to never start from scratch.

Whenever you have worked out the perfect logic in the script you're preparing, do one more thing. Take a reusable snapshot of the logic you've written and tested and save it in a template for the next time you need to do something similar. You'll save yourself both development and debugging time.

Don't start from scratch

Work out the syntax for various things that you might do routinely in your scripts -- especially

anything you do that might be fairly complicated. Set up examples in a directory and use them to get a head start on your coding. Here are some examples:

testing arguments

Checking if the first argument is numeric:

if ! [ "$1" -eq "$1" 2> /dev/null ]
then
  echo "ERROR: $1 is not numeric"
  exit 1
fi

Notice how we are throwing standard error into the bit bucket. All we really want to know is whether the test had a problem. If the argument is not numeric, the test inside the brackets fails and the !, which reverses the condition, succeeds. So, we execute the commands in the then clause and exit with an error.

Checking if three arguments were provided:

if [ $# != 3 ]; then
    echo "ERROR: 3 arguments expected"
    exit 1
fi

This one's pretty easy. We're just checking $# (the number of arguments) to see if it's what the script requires. This doesn't go as far as checking that the arguments are of the right type or whether they've be provided in the correct order.

building case statements

case $ans in
    [Yy][Ee][Ss]) rm err.log;;
    [Nn][Oo])     mv err.log err$$.log;;
    *)            echo "Please respond with yes or no"
                  exit 3;;
esac

There are many varieties of case statements that are possible. This one checks whether any form of "yes" or "no" was provided. If you want to also allow single-letter responses, you can do this, but you'll be accepting any response that starts with an "n" or a "y", regardless of case.

#!/bin/bash

echo -n "so, will it be yes or no?> "

read ans

case $ans in

Y*|y*) echo yes;;

N*|n*) echo no;;

*) echo Please respond with yes or no

exit 1;;

esac

looping through a file line at a time (not a word at a time)

Every now and then, I have to do a loop that will take each line from a file and process it as a complete line. Since I do this infrequently, I always have to stop and ask myself "Now, how do I do that again?". Unlike my everyday "for word in `cat file`" logic that breaks every line in separate words and loops on each of them, these while statements read and process a line at a time.

while read line
do
    name=$line
    echo "Text read from file - $name"
done < $1
while read line
do
    if [ "$list" == "" ]; then
        list=$line
    else
        list="$list, $line"
    fi
done < /tmp/u$$

using functions

I probably don't use functions often enough, but they're very useful -- both because they allow you to use the same code again and again in a complex script without having top present the same lines many times, but because in separating the logic of the script from the rest of what you're doing, they will generally make the entire script easier to read. Here, we've put our integer test into a function so that we can call it repeatedly.

function is_integer() {
    [ "$1" -eq "$1" > /dev/null 2>&1 ]
    return $?
}

crafting select statements

Select statements are another thing that I use rarely, so it's nice to have an example on hand when I need one. In the one below, we're asking the person running the script to select a file from a group of files ending in .dmp. Each selection will be presented in the list

select FILE in `ls *.dmp`
do
    if [ "$FILE" == "" ]; then
       echo "Bad selection"
       exit 2
    fi
    echo Will import database from $FILE
    break
done

The interaction will look something like this:

Please select db dump from the files listed below
1) mon.dmp
2) tue.dmp
3) wed.dmp
#? 2
Ready to import database from tue.dmp

You can just drop your scripts into a templates directory or you can use a repository like git or RCS for storing them. Saving examples of the logic you work out will make future script preparation faster and a little less frustrating.

Thanks to Karl Vogel for sharing his thoughts on using templates when preparing scripts.

This article is published as part of the IDG Contributor Network. Want to Join?

To express your thoughts on Computerworld content, visit Computerworld's Facebook page, LinkedIn page and Twitter stream.
Windows 10 annoyances and solutions
Shop Tech Products at Amazon
Notice to our Readers
We're now using social media to take your comments and feedback. Learn more about this here.