views:

1233

answers:

6

I know how to use Perl's Getopt::Long, but I'm not sure how I can configure it to accept any "--key=value" pair that hasn't been explicitly defined and stick it in a hash. In other words, I don't know ahead of time what options the user may want, so there's no way for me to define all of them, yet I want to be able to parse them all.

Suggestions? Thanks ahead of time.

+5  A: 

Getopt::Long doesn't do that. You can parse the options yourself...e.g.

my %opt;
my @OPTS = @ARGV;
for ( @OPTS ) {
  if ( /^--(\w+)=(\w+)$/ ) {
    $opt{$1} = $2;
    shift @ARGV;
  } elsif ( /^--$/ ) {
    shift @ARGV;
    last;
  }
}

Or modify Getopt::Long to handle it (or modify the above code to handle more kinds of options if you need that).

runrig
I forgot about the pass_through option of Getopt::Long. That's what you want, then parse remaining args as above, and add an 'else { die "Unknown option: $_\n" }' if you like.
runrig
+11  A: 

The Getopt::Long documentation suggests a configuration option that might help:

pass_through (default: disabled)
             Options that are unknown, ambiguous or supplied
             with an invalid option value are passed through
             in @ARGV instead of being flagged as errors.
             This makes it possible to write wrapper scripts
             that process only part of the user supplied
             command line arguments, and pass the remaining
             options to some other program.

Once the regular options are parsed, you could use code such as that provided by runrig to parse the ad hoc options.

Jon Ericson
A: 

This is a good time to roll your own option parser. None of the modules that I've seen on the CPAN provide this type of functionality, and you could always look at their implementations to get a good sense of how to handle the nuts and bolts of parsing.

As an aside, this type of code makes me hate Getopt variants:

use Getopt::Long;
&GetOptions(
    'name' => \$value
);

The inconsistent capitalization is maddening, even for people who have seen and used this style of code for a long time.

James Thompson
+2  A: 

I'm a little partial, but I've used Getopt::Whatever in the past to parse unknown arguments.

Josh McAdams
Sounds interesting. What does it do? Can it be used in conjunction with the Getopt::Long pass_through option?
Jon Ericson
A: 

From the documentation:

Argument Callback

A special option 'name' <> can be used to designate a subroutine to handle non-option arguments. When GetOptions() encounters an argument that does not look like an option, it will immediately call this subroutine and passes it one parameter: the argument name.

Well, actually it is an object that stringifies to the argument name.

For example:

    my $width = 80;
    sub process { ... }
    GetOptions ('width=i' => \$width, '<>' => \&process);

When applied to the following command line:

    arg1 --width=72 arg2 --width=60 arg3

This will call process("arg1") while $width is 80, process("arg2") while $width is 72, and process("arg3") while $width is 60.

This feature requires configuration option permute, see section "Configuring Getopt::Long".

Brad Gilbert
A: 

Potentially, you could use the "Options with hash values" feature.

For example, I wanted to allow users to set arbitrary filters when parsing through an array of objects.

GetOptions(my $options = {}, 'foo=s', 'filter=s%')

my $filters = $options->{filter};

And then call it like

perl ./script.pl --foo bar --filter baz=qux --filter hail=eris

Which would build something like..

$options = {
          'filter' => {
                        'hail' => 'eris',
                        'baz' => 'qux'
                      },
          'foo' => 'bar'
        };

And of course $filters will have the value associated with 'filter'

Good luck! I hope someone found this helpful.

Octoberdan