Reputation: 1965
I would like to specify more arguments for one option:
#!/usr/bin/perl -w
use Getopt::Std qw[getopts];
getopts('a:');
if($opt_a){
print "$opt_a\n";
}
and the use it like
$ foo.pl -a foo bar #...
and get each specified file/argument to an array in @opt_a
, is it possible?
Upvotes: 1
Views: 289
Reputation: 385657
Forget Getopt::Std for a second. How would a module (or any other code) know that bar
was an value for a
and not the first positional argument? Without a means of doing that, your grammar is ambiguous, and a parser can't be written for it.
This can be resolved in one of three ways. (Well, there are surely others.)
Solution 1 Allow the option and the flag to be repeated.
prog -a foo -a bar pos0 pos1
use Getopt::Long qw( GetOptions );
GetOptions(
'?|h|help' => \&help,
'a=s' => \my @opt_a,
)
or usage();
Solution 2 Use -a
to indicate what the positional arguments mean.
prog -a foo bar
use Getopt::Long qw( GetOptions );
GetOptions(
'?|h|help' => \&help,
'a' => \my @opt_a,
'b' => \my $opt_b,
)
or usage();
( $opt_a ? 1 : 0 ) + ( $opt_b ? 1 : 0 ) == 1
or usage("-a or -b must be specified, but not both");
my $opt_action = $opt_a ? 'a' : 'b';
@ARGV > 0
or usage("Invalid number of arguments");
Solution 3 Assume all values following -a
belong to -a
It turns out there is a standard way of marking the start of positional arguments. Using --
would distinguish option values from positional arguments.
prog -a foo bar -- pos0 pos1
use Getopt::Long qw( GetOptions );
GetOptions(
'?|h|help' => \&help,
'a=s{1,}' => \my @opt_a,
)
or usage();
However, --
is usually used to protect against positional arguments start with -
. It's a weird thing to have to protect against positional arguments not starting with -
.
It's also error-prone. People will be tempted to do the following:
prog -a foo pos0 # XXX Doesn't work as expected!
Notes:
help
and usage
.Upvotes: 2
Reputation: 37472
Apparently this is not possible with Getopt::Std
. But Getopt::Long
features an experimental feature that seems to provide what you want.
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
my @args_a;
GetOptions('a=s{1,}' => \@args_a);
foreach my $arg_a (@args_a) {
print("$arg_a\n");
}
When the above is called with -a x y z
then @args_a = ('x', 'y', 'z')
.
But, as ikegami pointed out, you have to find a way to distinguish "flagless" parameters (if you intend to have such). You can use --
to separate them. A call with -a x y z -- n m o
would result in @args_a = ('x', 'y', 'z')
and @ARGV = ('n', 'm', 'o')
.
And of course it's a risk to write a program that relies on an experimental feature which might be removed in later versions.
An alternative, that doesn't rely on an experimental feature (but still needs Getopt::Long
), would be to allow multiple -a
s.
...
GetOptions('a=s' => \@args_a);
...
would do that. Here to get @args_a = ('x', 'y', 'z')
, the call needs to be with -a x -a y -a z
.
Upvotes: 2