Lazer
Lazer

Reputation: 94820

How to group the arguments while using Getopt in Perl?

To a perl script that I am writing, there can be a lot (~50) of command line options provided. Most of them are optional, so a call will have only some of the options provided.

I am using Getopt::Long but it does not allow me to use GetOptions more than once. As a result, I have to use all the command line options in one GetOptions call.

Is there some good way to group the options while using GetOptions?

$ cat test.pl
use strict;
use warnings;
use Getopt::Long;

my ($a, $b, $c, $d);

GetOptions ('a=s' => \$a, 'b=s' => \$b);
GetOptions ('c=s' => \$c, 'd=s' => \$d);

print "a = $a\nb = $b\nc = $c\nd = $d\n";

$ perl test.pl -a=AA -b=BB -c=CC -d=DD
Unknown option: c
Unknown option: d
Use of uninitialized value in concatenation (.) or string at test.pl line 10.
Use of uninitialized value in concatenation (.) or string at test.pl line 10.
a = AA
b = BB
c = 
d = 
$

Upvotes: 1

Views: 2820

Answers (4)

Ben Martin
Ben Martin

Reputation: 1510

The most direct answer is to use Getopt::Long::Configure like so:

use strict;
use warnings;
use Getopt::Long;

my ($a, $b, $c, $d);

Getopt::Long::Configure( qw(pass_through) );
GetOptions ('a=s' => \$a, 'b=s' => \$b);

Getopt::Long::Configure( qw(no_pass_through) );
GetOptions ('c=s' => \$c, 'd=s' => \$d);

print "a = $a\nb = $b\nc = $c\nd = $d\n";

Note that you should make sure that your last invocation of GetOptions should be configured with no_pass_through to make sure that you get warnings about unknown options.

% perl test_getop.pl -a AA -b BB -c CC -d DD -e EE
Unknown option: e
a = AA
b = BB
c = CC
d = DD

Upvotes: 2

Zaid
Zaid

Reputation: 37146

It may be a good idea to store your options in a hash instead:

See Getopt::Long : Storing options values in a hash :


Sometimes, for example when there are a lot of options, having a separate variable for each of them can be cumbersome. GetOptions() supports, as an alternative mechanism, storing options values in a hash.

To obtain this, a reference to a hash must be passed as the first argument to GetOptions(). For each option that is specified on the command line, the option value will be stored in the hash with the option name as key. Options that are not actually used on the command line will not be put in the hash, on other words, exists($h{option}) (or defined()) can be used to test if an option was used. The drawback is that warnings will be issued if the program runs under use strict and uses $h{option} without testing with exists() or defined() first.

my %h = ();
GetOptions (\%h, 'length=i');       # will store in $h{length}

For options that take list or hash values, it is necessary to indicate this by appending an @ or % sign after the type:

GetOptions (\%h, 'colours=s@');     # will push to @{$h{colours}}

To make things more complicated, the hash may contain references to the actual destinations, for example:

my $len = 0;
my %h = ('length' => \$len);
GetOptions (\%h, 'length=i');       # will store in $len

This example is fully equivalent with:

my $len = 0;
GetOptions ('length=i' => \$len);   # will store in $len

Any mixture is possible. For example, the most frequently used options could be stored in variables while all other options get stored in the hash:

my $verbose = 0;                    # frequently referred
my $debug = 0;                      # frequently referred
my %h = ('verbose' => \$verbose, 'debug' => \$debug);
GetOptions (\%h, 'verbose', 'debug', 'filter', 'size=i');
if ( $verbose ) { ... }
if ( exists $h{filter} ) { ... option 'filter' was specified ... }

Upvotes: 6

Ven'Tatsu
Ven'Tatsu

Reputation: 3635

Normally arrays are flattened out into a single list before being passed to a function, although some functions override this behavior. Using this you can define arrays of option groups and pass the list of arrays to GetOptions.

use strict;
use warnings;
use Getopt::Long;

my ( $opt_a, $opt_b, $opt_c, $opt_d );

my @opt_group_1 = ( 'a=s' => \$opt_a, 'b=s' => \$opt_b );
my @opt_group_2 = ( 'c=s' => \$opt_c, 'd=s' => \$opt_d );
GetOptions( @opt_group_1, @opt_group_2 );

print "a = $opt_a\nb = $opt_b\nc = $opt_c\nd = $opt_d\n";

You can combine this with storing values in a hash to prevent having to create a huge number of option variables as Zaid mentioned.

use strict;
use warnings;
use Getopt::Long;

my @opt_group_1 = ( 'a=s', 'b=s' );
my @opt_group_2 = ( 'c=s', 'd=s' );

my %opt;

GetOptions( \%opt, @opt_group_1, @opt_group_2 );

print "a = $opt{a}\nb = $opt{b}\nc = $opt{c}\nd = $opt{d}\n";

Upvotes: 0

cjm
cjm

Reputation: 62099

What's wrong with:

GetOptions(
  'a=s' => \$a,
  'b=s' => \$b,
  'c=s' => \$c,
  'd=s' => \$d,
);

Or, if they're all short, you could do:

GetOptions(
  'a=s' => \$a,   'b=s' => \$b,
  'c=s' => \$c,   'd=s' => \$d,
);

(Note that it's a bad idea to use $a and $b for anything except sort comparisions.)

Upvotes: 1

Related Questions