如何在 perl 中为 Getopt::Std 中的一个选项提供更多参数(以 space 分隔)?

How to provide more arguments (separated by space) for one option in Getopt::Std in perl?

我想为一个选项指定更多参数:

#!/usr/bin/perl -w
use Getopt::Std qw[getopts];

getopts('a:');

if($opt_a){
    print "$opt_a\n";
}

并像这样使用它

$ foo.pl -a foo bar #...

并把每一个指定的file/argument放到@opt_a中的一个数组中,有可能吗?

暂时忘记Getopt::Std。模块(或任何其他代码)如何知道 bara 的值而不是第一个位置参数?如果没有这样做的方法,您的语法就会有歧义,并且无法为其编写解析器。

这可以通过以下三种方式之一解决。 (好吧,肯定还有其他人。)

解决方案 1 允许重复选项和标志。

prog -a foo -a bar pos0 pos1
use Getopt::Long qw( GetOptions );

GetOptions(
   '?|h|help' => \&help,
   'a=s'      => \my @opt_a,
)
   or usage();

解决方案 2 使用 -a 说明位置参数的含义。

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");

解决方案 3 假设 -a 之后的所有值都属于 -a

原来有一种标准方法来标记位置参数的开始。使用 -- 会将选项值与位置参数区分开来。

prog -a foo bar -- pos0 pos1
use Getopt::Long qw( GetOptions );

GetOptions(
   '?|h|help' => \&help,
   'a=s{1,}'  => \my @opt_a,
)
   or usage();

但是,-- 通常用于防止以 - 开头的位置参数。必须防止以 -.

开头的位置参数 not 是一件很奇怪的事情

它也很容易出错。人们会被诱惑去做以下事情:

prog -a foo pos0    # XXX Doesn't work as expected!

备注:

  1. 我用了Getopt::Long。如果Getopt::Std也能做到,那太好了。我用我所知道的。
  2. 有关 helpusage 的实施示例,请参阅

显然 Getopt::Std 无法做到这一点。但是 Getopt::Long 有一个 experimental feature 似乎可以满足您的需求。

#!/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");
}

当用 -a x y z 调用上面的代码时,然后 @args_a = ('x', 'y', 'z').

但是,正如 ikegami 指出的那样,您必须找到一种方法来区分“无标志”参数(如果您打算使用这种参数)。您可以使用 -- 来分隔它们。使用 -a x y z -- n m o 的调用将导致 @args_a = ('x', 'y', 'z')@ARGV = ('n', 'm', 'o').

当然,编写依赖于实验性功能的程序是有风险的,该功能可能会在以后的版本中被删除。

另一种不依赖于实验性功能(但仍需要 Getopt::Long)的替代方法是允许多个 -a

...
GetOptions('a=s' => \@args_a);
...

会那样做。这里要获取@args_a = ('x', 'y', 'z'),调用需要带-a x -a y -a z.