Elegance of Reason

Saturday, December 03, 2005

Improving shell scripts

Although there is no reason to exempt shell scripts from good programming practices, many scripts showing signs of such neglect can readily be found over the Internet. This is sad, because it brings shell programming down to the level of Visual Basic, and because it can be easily avoided.

Consider a common task: upon encountering a condition which does not allow script execution to continue, show a diagnostic and exit. Most scripts do that, it's how they do it that could use some improvement. Consider a first attempt:

warn() {
echo 1>&2 "$0: $1"

die() {
warn "$1"; exit ${2:-1}

Here the warn() function anticipates a variation of the initial use case: the script encountered a condition which is supposedly of some interest to the user, but does not prevent the script from proceeding with execution. The die() function, also borrowed from Perl, just puts it to good use and exits.

The message is printed on standard error: this is an important and too often overlooked behavior, which makes parsing standard output easier and therefore the script more useful in pipelines.

Furthermore, according to Unix conventions, the message begins with the command name $0 followed by a semicolon, a space, and the diagnostic proper; this helps when a script is invoked by another script, to sort out who produced the diagnostic.

Last, die() exits the script with a non-zero return code, again according to Unix conventions. The actual exit code can be left unspecified, for the convenience of the caller in code such as:

tar --version >/dev/null 2>&1 || die "cannot find tar(1)"
tar -c -f /dev/nst0 /opt || warn "Backup failed"

The above code is not completely satisfying, but at least offers a starting point for putting some self-respect in shell scripts. The Perl module Pod::Usage provides some directions which can be borrowed to improve it, and there is also an instance of poor quoting, which will be fixed in a forthcoming post.


Post a Comment

Links to this post:

Create a Link

<< Home