Can I bind two different input flags using Getopt::Long lib in perl?

55 Views Asked by At

Lets take a simple example: I wanto to have the following input in my script:

[
{foo => date_1},
{foo2=> date_2},
{foo3=> undef}, # there was no input
... # probably more in the future
]

So using something similar to this:

use strict;
use warnings;
use utf8;
use Getopt::Long qw(GetOptions);

my @foos;
my @dates;

# INPUT
GetOptions(
    'foo|f:s'                                       => \@foos,
    'date|d:s'                                      => \@dates,
# 'help|h'   => \&help,
) or die "Invalid options passed to $0\n"; 

I want to be able to call the script with somehing similar to this:

perl script.pl --foo "Go with 1" --foo "Go with 2" --date "date1" --date "date2"

And then be able to do somethig like:

foreach my $i (0..scalar(@foos)){
  print $foos[$i] . " " . $dates[$i] . "\n";
}

And obtain:

Go with 1 date1
Go with 2 date2

Why I want to do this?: I loop over an uncertain amount of foos for one function. In another function I want to loop again through the foos and print a date associated to it if present.

What I would like to avoid: Having to create a flag for every element of foos, like the following:

GetOptions(
    'foo|f:s'                                               => \@foos,
    'date-foo-1|df1:s'                                      => \$dates_foo_1,
    'date-foo-2|df2:s'                                      => \$dates_foo_2,
# 'help|h'   => \&help,
) or die "Invalid options passed to $0\n"; 

I think what I would to be able to do is having an optional flag associated to another flag but I have not been able to find anything related.

1

There are 1 best solutions below

5
Dave Cross On

Your code already does what you want.

use strict;
use warnings;
use utf8; # This is unnecessart
use Getopt::Long qw(GetOptions);

my @foos;
my @dates;

# INPUT
GetOptions(
    'foo|f:s'  => \@foos,
    'date|d:s' => \@dates,
# 'help|h'   => \&help,
) or die "Invalid options passed to $0\n";

foreach my $i (0 .. scalar(@foos)){
  print $foos[$i] . " " . $dates[$i] . "\n";
}

The output is:

Go with 1 date1
Go with 2 date2
Use of uninitialized value in concatenation (.) or string at opts.pl line 17.
Use of uninitialized value in concatenation (.) or string at opts.pl line 17.

There's a warning displayed because your array-walking code has a bug. You don't want to walk 0 .. scalar @foos as scalar @foos gives 2 and the highest index in @foos is 1.

Instead of scalar @foos, you can use $#foos to get the highest index in @foos.

foreach my $i (0 .. $#foos){
  print $foos[$i] . " " . $dates[$i] . "\n";
}

It's also worth pointing out that

print $foos[$i] . " " . $dates[$i] . "\n";

Can be written more simply as:

print "$foos[$i] $dates[$i]\n";

Update: In a situation where you need two lists of the same length, you might also look at the documentation for Options with hash values