...
The first thing you will notice about this script is that there is a lot of argument and error checking -- more than the actual "work" code. This is a hallmark of a well-written shell script, especially one that will be run at TACC by many processors at a time.
...
| Code Block |
|---|
err() {
echo "$1...exiting";
exit 1; # any non-0 code means error
}
|
This function takes one argument, echoes it along with some boilerplate text ("...exiting") and exits. You might call it like this from a shell script:
...
Why write a function this simple? Because we're going to build on it, writing more specialized error checking functions, and we want all of them to print out the boilerplate text ("...exiting") before they exit. If we want to change this boilerplate text we only have to change it in one function! And, since the text is well-known and not likely to be written by successful programs, we can easily grep for it in our execution log files. For a single file:
...
If the filename passed as the first argument exists, nothing happens when ckFile is called. If the file does not exist, the shell script exits at the line where the ckFile called after printing out a diagnostic message that includes our boilerplate (because this function calls err).
The function can be called with one or two arguments, for example:
| Code Block |
|---|
ckFile myFile.fastq
ckFile myFile.fastq "Input fastq"
|
Here is another function, ckRes, that checks the result code passed in as its first argument. It uses the text passed as its second argument either to print a diagnostic message (by calling our friend err) or to print a message showing that the task completed, and when:
| Code Block |
|---|
ckRes() { if [ "$1" == "0" ]; then echo "..Done $2 `date`"; else err "$2 returned non-0 exit code $1"; fi } |
A time-honored convention is that all programs whether shell scripts, built-in shell commands, user-written scripts or other programs, exit with a return code of 0 if all went well, or with any other integer return code if not. Calling programs can then check the return code to see if something went wrong. In the bash shell, the just-executed program's return code is placed in the special xxx variable, which should be checked right away because doing anything else in the shell will reset it. So for example, to check whether a call to bwa aln returned 0 (ok, keep going) or not (bad, exit with message):
| Code Block |
|---|
bwa aln $REF_PFX $IN_FQ > $OUT_PFX.sai
ckRes $? "bwa aln"
|
If the alignment was successful, a message like this will be written to the execution log:
| Code Block |
|---|
..Done bwa aln Sun May 20 15:00:03 CDT 2012
|
If the program's return code was non-zero, a message like this will be written, and the script will terminate.
| Code Block |
|---|
bwa aln returned non-0 exit code 1...exiting
|
And yet one more wrinkle. For a further refinement of file checking, we also check that the file's size is non-0. Why? Because:
- Programs don't always return a non-0 return code.