Tuesday, November 13, 2007

Trapping Signals - Perl vs. Shell

Hey there,

It's probably a fact that most scripts you ever check out (Perl or shell) perform a function. They maybe even do some error checking and argument parsing. It's strange that it's relatively rare to see a script that actually traps signals and reacts to them. I've actually been asked by folks, that I know can script, what the heck the "trap" line at the top of one of my shell scripts is for.

The idea of trapping signals probably just doesn't fit well with the way the world works now. A lot of safety mechanisms are built into programming and scripting languages and, therefore, the scripter or programmer has less to worry about. Java will clean up your garbage for you. My kid won't even do that for me if I pay him :)

There are plenty of times, though, that it makes sense to trap signals in your scripts (or write a function file or something like that) so that you can maintain some sense of virtually guaranteed order.

For instance, if you've got a great script that works like a charm, it could still have some holes in it. Perhaps you write out to temporary files to make editing alterations, or touch lock files to prevent multiple versions of your script from running simultaneously. Any of these things could become an issue the next time your script is run if, for instance, a user types control-C right in the middle of running it. Now you've got temporary files or locks set that shouldn't be, and your next script run will act logically and assume that conditions exist that actually don't.

Thankfully, it's very easy to take care of these sorts of conditions in both the shell and Perl. In the shell, I usually include a line right near the top that looks something like this (here we're just worried about the control-C):

trap 'rm /tmp/.lockfile;exit' 2

Simple enough, right? That line makes it so your script will catch that control-C (Represented on the right side by the signal's number: 2) the user enters while your script is running and execute the code block in between the single quotes. In this instance we're deleting our .lock file and exiting cleanly. Multiple commands can be put together using semi-colons, just like on the command line.

In Perl it's pretty much the same but can be a little more complex, or maybe convoluted. For our example, using it to do anything special would be overkill, but Perl has much more robust signal handling capabilites that we aren't using here. That same trap line, above, in Perl would look like this - almost always has to be a two-parter unless you just want to use default handlers like 'IGNORE' or 'DEFAULT':

$SIG{'INT'} = 'INT_handler';

then somewhere else down the script you've got your handler subroutine:

sub INT_handler {
unlink("/tmp/.lock");
exit(0);
}


When it comes right down to it, depending on what you want to do, the shell suits certain purposes more simply, and Perl suits most of the others. There are probably 10, 20 or more custom Perl modules out there to make the job even easier.

We'll take a look at signal handling and how it can enhance your scripts usability in a future post. For now, please stop INTerruping :P

Best Wishes,

, Mike