Use Getopt::Long even if you don't think you need to

Thread over on perlmonks talks about Tom Christiansen's assertion that you should use it, by default, even when you only have one command-line argument to parse:

What seems to happen is that at first we just want to add--oh say for example JUST ONE, SINGLE LITTLE -v flag. Well, that's so easy enough to hand-hack, that of course we do so... But just like any other piece of software, these things all seem to have a way of overgrowing their original expectations... Getopt::Long is just *wonderful*, up--I believe--to any job you can come up with for it. Too often its absence means that I've in the long run made more work for myself--or others--by not having used it originally. [Emphasis mine -- Andy]

I can't agree more. I don't care if you use Getopt::Long or Getopt::Declare or Getopt::Lucid or any of the other variants out there. You know know know that you're going to add more arguments down the road, so why not start out right?

Yes, it can be tricky to get through all of its magic if you're unfamiliar with it, but it's pretty obvious when you see enough examples. Take a look at prove or ack for examples. mech-dump is pretty decent as an example as well:

    'user=s'        => \$user,
    'password=s'    => \$pass,
    forms           => sub { push( @actions, \&dump_forms ); },
    links           => sub { push( @actions, \&dump_links ); },
    images          => sub { push( @actions, \&dump_images ); },
    all             => sub { push( @actions, \&dump_forms, \&dump_links, \&dump_images ); },
    absolute        => \$absolute,
    'agent=s'       => \$agent,
    'agent-alias=s' => \$agent_alias,
    help            => sub { pod2usage(1); },
) or pod2usage(2);

Where the value in the hashref is a variable reference, the value gets stored in there. Where it's a sub, that sub gets executed with the arguments passed in. That's the basics, and you don't have to worry about anything else. Your user can pass --abs instead of --absolute if it's unambiguous. You can have mandatory flags, as in agent=s, where --agent must take a string. On and on, it's probably got the functionality you need.

One crucial reminder: You must check the return code of GetOptions. Otherwise, your program will carry on. If someone gives your program an invalid argument on the command-line, then you know that the program cannot possibly be running in the way the user intended. Your program must stop immediately.

Not checking the return of GetOptions is as bad as not checking the return of open. In fact, I think I smell a new Perl Critic policy....



Tim Bunce said:

I'd like to put in a good word for Getopt::Euclid by Damian Conway. It makes "add an option by simply documenting it" a reality.

Especially using the

  use Getopt::Euclid qw( :vars );
style which makes it create the traditional $opt_foo variables. It's a little hidden in the docs.

It's already a great options module but does need a little love and Damian is swamped. Any volunteers?

Sam Vilain said:

Using Scriptalicious, you get Getopt::Long built-in with less typing (just "getopt"). It's even in Debian etch. The example: -v, is a standard option, so you can write:

use Scriptalicious;
mutter "This message will only appear with -v";

It also ships with a bunch of other useful bits and pieces that are useful for writing those one-shot scripts, such as running commands quietly (showing the command line with -v), prompting for user input, and even reading RC files based on the options you pass to 'getopt'. As a bonus, it's got no hard dependencies (well, other than Term::ReadKey if you use prompt_passwd, and YAML for RC reading).

That being said, I think that an approach like MooseX::Getopt is probably more elegant in the long run.

For the odd script, I like GetOpt::Easy, which is well named.

use GetOpt::Easy;

"a-all v=verbose",
"usage: journal [-a] [-v verbosity ] [-H] mm/dd/yy]",

$verbosity = $O{verbose} if $O{verbose};
do_all() if $O{all} };

The above will print the usage message if a bad option is given. It will print its pod if a -H is given;
this is produced by the third argument, 'H';

Easy doesn't handle --long-style options, but I haven't missed them.

Leave a comment

About this Entry

This page contains a single entry by Andy Lester published on May 25, 2008 9:20 PM.

Pragmatic Programmer on estimating was the previous entry in this blog.

Scrabble cheating with Perl one-liners is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Other Perl Sites

Other Swell Blogs

  • geek2geek: An ongoing analysis of how geeks communicate, how we fail and how to fix it.