Wednesday, November 2, 2005

How to Arg a Perl Script

Arg, that is a good script!
This image is trademarked.Perl is often associated with camels. It has been that way ever since O'Reilly's book Programming Perl came out with a camel on the cover. Beyond the even-toed ungulate mascot, I don't have much good to say about Perl. I'll take Python or Ruby over it any day of the week. (I apologize profusely to Perl afficianadoes for my poor Perl skills. I just have no interest in being good at it. I was raised on Java and OO. I know, I know, Perl does OO too, but looking at OO Perl is like watching an 80 year old man popping his booty to the Black Eyed Peas. It is just plain wrong.)

Despite this aversion, I use Perl for occasional backend jobs such as importing and exporting data to and from databases, archiving files, and running Lucene indexer jobs. These scripts I am talking about normally run out of cron, but occasionally get run by hand. I like to make my scripts as nice to use as possible, and that means configuration files and command line args. A script that takes parameters is a script that has been "argged", and a script that has been well argged is one that lets you specify behavior right from the command line, and offers you a usage screen when you have done something wrong. Well argged scripts are dreamy, even if they are written in stinky old Perl.

I use the AppConfig module for argging my Perl. Here is a code snippet from a script that reads in arguments from a config file, and from the command line using AppConfig.
[code lang="perl"]
use AppConfig;

#################################################################
# Read Command Line Arguments
#################################################################
# Create a new AppConfig object
my $config = AppConfig->new();

# Define the configuration variables
$config->define(
"help|h!",
"all|a=s",
"create|create=s"
);

# Read in config from the file
fatal_error("Failed to read config file") if !$config->file($config_file);

# Read command line options
$config->args();

# display a help message and exit if help is selected
usage() if $config->help;

[/code]
The interesting (and confusing) thing here is the $config->define() method. This method takes a list of strings of the form "var | abbrev filetype" Notice I have done 3 different types of things (I wish I had line numbers on this). The first one "help|h!" tells AppConfig that I am defining a variable called 'help' that can be specified on the command line with '-h', and the "!" tells us it is a boolean value, meaning $config->help will be "1" when somebody passes your script the '-h' parameter. The second one "all|a=s" tells AppConfig I am declaring a variable 'all' that can be specified on the command line with '-a', and it is expecting a string value. So an example of usage would be ./myscript.pl -a this_example_sucks. If we were to print the value of $config->all at this point it would print out "this_example_sucks." Finally, the third thing I am doing is the same as the second thing, but the argument is '-create' instead of '-c' or something like that.

This script is also reading parameters from a file. This code $config->file($config_file); is looking for a file with parameters specified like an .ini file or just a vanilla configuration file like this one below.

#
# sample config
# $Id$
#

#a silly config value
all = PENCILS_COME_FROM_PENNSYLVANIA

#more silly stuff
create = VESTS_FROM_VEST_VIRGINIA

One quirk about this system is that you can only put parameters in the config file for which you have defined with the $config->define() method. If you start making up parameters in there you will get errors. There is way more stuff that AppConfig can do, and I have just enough patience to scratch the surface here (spent some time looking for examples of usage with AppConfig). So you should read the perlDocs for it and man pages and you will know more than me in a hurry. But like I said, I don't WANT to know about Perl.

No comments: