在较新的 Getopt::Long 中如何设置默认可选值

In newer Getopt::Long How do I set default optional values

在 Perl 的 Getopt::Long 版本 2.39 中我可以使用

use Getopt::Long qw( :config gnu_getopt );
GetOptions(
   \my %opts, 
   "codon-view|c:20",    # Optional value, default 20
   "consensus|C:50", 
   ...
)

表明如果我使用 -c 默认值将是 20 放在 %opts 键下 codon-view-c 给出但没有明确的值时在那儿。另一方面,未提供 -c--codon-view,则散列 table 中的值不会存储在 %opts.

在 2.48 中,这不再有效,我在 Getopt::Long's documentation

中看不到
$ perl -E'
   use Getopt::Long qw( :config gnu_getopt );
   say $Getopt::Long::VERSION;
   GetOptions(\my %opts, "codon-view|c:20");
   say $opts{"codon-view"} // "[undef]"
' -- -c
2.39
20

$ perl -E'
   use Getopt::Long qw( :config gnu_getopt );
   say $Getopt::Long::VERSION;
   GetOptions(\my %opts, "codon-view|c:20");
   say $opts{"codon-view"} // "[undef]"
' -- -c
2.48
[undef]

我怎样才能实现旧的行为?

求助!

GetOptions() 调用之前设置默认值。如果命令行中没有提供该选项,则不会覆盖默认值。

$ perl -MGetopt::Long -E '$c=20;GetOptions("c=i"=>$c); say $c' -- -c 14
14

$ perl -MGetopt::Long -E '$c=20;GetOptions("c=i"=>$c); say $c' --
20

Getopt::Long 文档中有 a trivial example

我喜欢将我的选择分配给哈希..

GetOptions(\ my %opt,
    'codon-view|c:i',
);

if ( exists $opt{'codon-view'} ) {
    print "User triggered '-c' flag\n";
    $opt{'codon-view'} ||= 20;
    printf( "codon-view: %d\n", $opt{'codon-view'} );
}

现在,如果用户不带参数运行 ./you-app -c,则会创建 $opt{c} 键,但它的值为 undef,因此您需要检查它是否由 [= 触发14=].

仅当左侧为 falsey(通常为 undef)时,||= 运算符才将右侧分配给左侧。一个警告是,如果有人 -c 0 它将分配默认值......但我将继续并假设 0 可能是你的标志的一个坏参数。

这是 2.48 中引入的更改。

$ perl -E'
   use Getopt::Long qw( :config gnu_getopt );
   say $Getopt::Long::VERSION;
   GetOptions(\my %opts, "codon-view|c:20");
   say $opts{"codon-view"} // "[undef]"
' -- -c
2.47
20

$ perl -E'
   use Getopt::Long qw( :config gnu_getopt );
   say $Getopt::Long::VERSION;
   GetOptions(\my %opts, "codon-view|c:20");
   say $opts{"codon-view"} // "[undef]"
' -- -c
2.48
[undef]

我不确定,但我认为这是无意的,所以我提交了 bug report


use Getopt::Long qw( :config gnu_getopt );

的缩写
use Getopt::Long qw( :config gnu_compat bundling permute no_getopt_compat );

您在使用 gnu_compat 方面投入了多少?

$ perl -E'
   use Getopt::Long qw( :config gnu_getopt );
   say $Getopt::Long::VERSION;
   GetOptions(\my %opts, "codon-view|c:20");
   say $opts{"codon-view"} // "[undef]"
' -- -c
2.48
[undef]

$ perl -E'
   use Getopt::Long qw( :config gnu_compat bundling permute no_getopt_compat );
   say $Getopt::Long::VERSION;
   GetOptions(\my %opts, "codon-view|c:20");
   say $opts{"codon-view"} // "[undef]"
' -- -c
2.48
[undef]

$ perl -E'
   use Getopt::Long qw( :config bundling permute no_getopt_compat );
   say $Getopt::Long::VERSION;
   GetOptions(\my %opts, "codon-view|c:20");
   say $opts{"codon-view"} // "[undef]"
' -- -c
2.48
20

gnu_compat controls whether --opt= is allowed, and what it should do. Without gnu_compat, --opt= gives an error. With gnu_compat, --opt= will give option opt and empty value. This is the way GNU getopt_long() does it.

因此,如果您同意 --codon-view= 将零分配给 $opts{"codon-view"},只需使用

use Getopt::Long qw( :config bundling permute no_getopt_compat );

而不是

use Getopt::Long qw( :config gnu_getopt );

这是另一个可能但不太好的解决方案:包括 Getopt::Long.pm 的副本,它只有一个文件,但我已将包命名空间更改为不同的名称,例如MyPackage::GetoptLong。

这不是一个理想的答案,但如果您需要一些东西来保持兼容性并且没有更好的 ikegami 解决方案,请牢记这一点。