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 while read line
do
if [ "$list" == "" ]; then
list=$line
else
list="$list, $line"
fi
done 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.




