Perl GetOpt::Long 多个参数和可选参数

3

这是我的第一篇在stackoverflow上的帖子。 :)

我正在尝试使用GetOpt::Long解决此场景。

./myscript -m /abc -m /bcd -t nfs -m /ecd -t nfs ...

-m是挂载点,-t是文件系统类型(可以放置,但不是必需的)。

  Getopt::Long::Configure("bundling");
  GetOptions('m:s@' => \$mount, 'mountpoint:s@' => \$mount,
             't:s@' => \$fstype, 'fstype:s@'  => \$fstype)

这不对,我无法匹配正确的挂载点和文件系统类型。

./check_mount.pl -m /abc -m /bcd -t nfs -m /ecd -t nfs
$VAR1 = [
          '/abc',
          '/bcd',
          '/ecd'
        ];
$VAR1 = [
          'nfs',
          'nfs'
        ];

我需要填写未指定的文件系统类型,例如使用"undef"值。 对我来说最好的解决方案是获取哈希表,例如...

%opts;
$opts{'abc'} => 'undef'
$opts{'bcd'} => 'nfs'
$opts{'ecd'} => 'nfs'

可以吗?谢谢。


你试图强制规定选项的非常特定的顺序,但我认为这不是很常见或直观的。如果我是你应用程序的用户,我会期望 -m foo -t bar-t bar -m foo 是相同的。你也许可以使用 Getopt::Long 来实现这一点,但我认为采用不同的设计会更好。 - ThisSuitIsBlackNot
2个回答

1

来自文档的“参数回调”部分:

When applied to the following command line:
    arg1 --width=72 arg2 --width=60 arg3

This will call process("arg1") while $width is 80 , process("arg2") while $width is 72 , and process("arg3") while $width is 60.

EDIT: Add MWE as requested.

use strict;
use warnings;
use Getopt::Long qw(GetOptions :config permute);

my %mount_points;
my $filesystem;

sub process_filesystem_type($) {
    push @{$mount_points{$filesystem}}, $_[0];
}

GetOptions('t=s' => \$filesystem, '<>' => \&process_filesystem_type);

for my $fs (sort keys %mount_points) {
    print "$fs : ", join(',', @{$mount_points{$fs}}), "\n";
}

./test -t nfs /abc /bcd -t ext4 /foo -t ntfs /bar /baz

ext4: /foo

nfs: /abc, /bcd

ntfs: /bar, /baz

请注意,输入的顺序为文件系统类型,然后是挂载点。这与原始帖子中的解决方案相反。


1
如果您提供一个基于OP问题的工作示例,那将极大地帮助。 - stevieb
@stevieb 我按照你的要求添加了最小可行示例(MWE)。可能在此之前应该这样做,但我有点懒。 - Tim

1
这个不容易直接使用Getopt::Long实现,但如果你可以稍微改变参数结构,比如改为
./script.pl --disk /abc --disk /mno=nfs -d /xyz=nfs

以下内容将帮助您达到您想要的目标(请注意,缺少类型将显示为空字符串,而不是undef):
use warnings;
use strict;

use Data::Dumper;
use Getopt::Long;

my %disks;

GetOptions(
    'd|disk:s' => \%disks, # this allows both -d and --disk to work
);

print Dumper \%disks;

输出:

$VAR1 = {
          '/abc' => '',
          '/mno' => 'nfs',
          '/xyz' => 'nfs'
        };

1
你甚至不需要自己进行split。只要小心挂载点中包含的=即可。链接 - ThisSuitIsBlackNot
好的,@ThisSuitIsBlackNot 的建议很好。在我的多年经验中,我不知道文档中还有这一部分 :) 这很方便!(回答已更新) - stevieb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接