在 Perl 中使用 Getopt 时如何对参数进行分组?

Posted

技术标签:

【中文标题】在 Perl 中使用 Getopt 时如何对参数进行分组?【英文标题】:How to group the arguments while using Getopt in Perl? 【发布时间】:2011-05-08 23:43:06 【问题描述】:

对于我正在编写的 perl 脚本,可以提供很多(约 50 个)命令行选项。它们中的大多数是可选的,因此调用将只提供一些选项。

我正在使用Getopt::Long,但它不允许我多次使用GetOptions。因此,我必须在一个 GetOptions 调用中使用所有命令行选项。

在使用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 = 
$

【问题讨论】:

【参考方案1】:

有什么问题:

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

或者,如果它们都很短,你可以这样做:

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

(请注意,将$a$b 用于除sort 比较之外的任何内容都是一个坏主意。)

【讨论】:

正如我在问题中提到的那样,我大约有50个,如果不分组,很难跟踪它们。 @Lazer,那么您将不得不更好地解释“分组”的含义。 GetOptions 不关心它们的排列顺序;以对您有意义的任何顺序列出它们。【参考方案2】:

将您的选项存储在哈希中可能是个好主意:

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


有时,例如当有 很多选择,有一个单独的 他们每个人的变量可以是 麻烦。 GetOptions() 支持,如 另一种机制,存储 哈希中的选项值。

为了获得这个,对哈希的引用 必须作为第一个参数传递 到GetOptions()。对于每个选项 在命令行中指定, 选项值将存储在 以选项名称作为键的散列。 实际未使用的选项 命令行不会放入 换句话说,哈希, exists($hoption)(或defined())可以 用于测试是否使用了选项。 缺点是会发出警告 如果程序在使用中运行,则发出 严格并使用$hoption 使用exists()defined() 进行测试 首先。

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

对于采用列表或哈希值的选项,它是 有必要通过以下方式表明这一点 在后面附加一个 @ 或 % 符号 类型:

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

为了使事情更复杂,哈希可能 包含对实际的引用 目的地,例如:

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

这个例子完全等同于:

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

任何混合都是可能的。例如,最 经常使用的选项可能是 存储在变量中,而所有其他 选项存储在哈希中:

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 $hfilter )  ... option 'filter' was specified ... 

【讨论】:

+1 - 除其他原因外,一旦您开始进行任何复杂的开发,在单个变量中使用选项而不是可以作为一个整体传递给对象构造函数的哈希是非常痛苦的。【参考方案3】:

通常,数组在传递给函数之前会被展平为单个列表,尽管某些函数会覆盖此行为。使用它,您可以定义选项组数组并将数组列表传递给 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";

您可以将其与在哈希中存储值结合起来,以防止必须创建大量的选项变量,正如 Zaid 提到的那样。

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 = $opta\nb = $optb\nc = $optc\nd = $optd\n";

【讨论】:

【参考方案4】:

最直接的答案是像这样使用Getopt::Long::Configure:

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

请注意,您应确保上次调用 GetOptions 时应配置 no_pass_through,以确保收到有关未知选项的警告。

% 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

【讨论】:

以上是关于在 Perl 中使用 Getopt 时如何对参数进行分组?的主要内容,如果未能解决你的问题,请参考以下文章

Perl学习

Perl模块 Getopt::Long 解析

模块——Getopt::Long接收客户命令行参数和Smart::Comments输出获得的命令行参数内容

在Perl中使用Getopt::Long进行命令行解析

在PerlShell和Python中传参与输出帮助文档

Getopt :: Long将包含空格的字符串转换为变量