【问题标题】:How can I pass Getopt::Long options to a subroutine that's also an option?如何将 Getopt::Long 选项传递给也是一个选项的子例程?
【发布时间】:2014-07-02 22:51:28
【问题描述】:

我正在尝试设置 Getopt::Long 来处理来自配置脚本的参数。

这是我的开胃菜;

#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;

my $config_file = '';

GetOptions (

    'config|c=s' => \$config_file,
    'add|a' => \&add_server,
    'del|d' => \&del_server,

);

sub add_server {

print "$config_file\n";

}

sub del_server {

# Left blank for now.

}

奇怪的是,当我用这样的东西运行我的脚本时,我遇到了一个问题,

./config.pl -a -c config.xml

它不会打印-c 选项,但如果我这样运行它,

./config.pl -c config.xml -a

它按原样工作。

我想我明白原因了,这与订单执行有关吧?

问题是我该如何解决?我应该将 Getopt::Long 与 @ARGV 结合使用吗?

最终,我试图让命令行参数传递到我正在调用的子例程中。所以如果-a or --add 我希望-c or --config 的选项在被调用时传递到子程序中。

有什么想法吗?

【问题讨论】:

    标签: perl config subroutine getopt-long


    【解决方案1】:

    我认为不需要直接从GetOptions 调用中调用子例程。像这样控制顺序:

    use strict;
    use warnings;
    use Getopt::Long;
    
    my %opts = (config => '');
    
    GetOptions(\%opts, qw(
       config|c=s
       add|a
       del|d
    ));
    
    add_server() if $opts{add};
    del_server() if $opts{del};
    
    sub add_server {    
        print "$opts{config}\n";
    }
    
    sub del_server {}
    

    【讨论】:

      【解决方案2】:

      把这个例子稍微简化一下......

      use strict;
      use warnings;
      use Getopt::Long;
      
      my $config_file = '';
      
      GetOptions (
      
          'config|c=s' => \$config_file,
          'add|a' => sub{add_server($config_file);}
      );
      
      sub add_server
      {
      
          my $config=shift;
      
          if(defined($config))
          {
              print "Got this for a config file: $config\n";
          }
          else
          {
              print "No argument supplied to add_server\n";
          }
      
      }
      

      ... 运行config.pl -c blurg -a 返回输出Got this for a config file: blurg,运行config.pl -a -c blurg 返回Got this for a config file:

      所以,我怀疑正在发生的事情是选项是按给定顺序分配的。因此,在第一种情况下,$config_file 被分配给-c 参数,然后调用add_server 子例程(使用正确的参数),而在第二种情况下,add_server 在没有参数的情况下立即被触发,然后$config_file 已分配。

      除此之外,我建议将-a 设为布尔值,如果启用它(并且如果提供-c 的参数),则执行您想做的任何事情。

      【讨论】:

      • 回复:“您不能将选项直接关联到对命名子例程的代码引用。”完全错误。代码引用是代码引用。
      • @ikegami - 进一步阅读后,似乎这仅适用于可导出的消息。让我编辑。
      【解决方案3】:

      在遇到选项时会调用回调,因此在遇到 -c 之前会调用 add_server

      ./config.pl -a -c config.xml
      

      根据最新信息,您现在想要:

      use Getopt::Long qw( GetOptions );
      
      GetOptions(
         'a=s' => \my $opt_a,
         'd=s' => \my $opt_d,
         'h=s' => \my $opt_h,
         'p=s' => \my $opt_p,
      ) or usage();
      

      【讨论】:

      • 我只需要指定一个配置文件。
      • @Solignis,那为什么不直接做-a config.xml呢?
      • @Solignis,在这变成 20 个问题的游戏之前,你为什么不指定你想要的界面。
      • 最初的想法是让-a-d 控制您希望添加或删除的配置的特定部分。例如-a server01 会调用add_server 子例程,并带有server01 选项,但我不知道如何在不弄乱的情况下获得一个选项来做两件事。
      • @Solignis,Q2)哪个选项应该做两件事? Q3) 应该做哪两件事?
      【解决方案4】:
      GetOptions(
              'arg=s' => sub { print "$_[1]\n"; },
      );
      

      【讨论】:

      • 对不起,我以为它会自我解释。 GetOptions() 函数将参数数组@_ 传递给作为参数操作引用的whatever_you_like 函数。该数组包含 $_[0] 中参数的全名 (arg),它的值在 $_[1] 中。
      【解决方案5】:

      在 Getopt::Long 上启用 pass_through 选项,以便它忽略未知选项,然后为您的选项调用一次 GetOptions,再次禁用它,然后再次为您的命令使用 GetOptions。

      【讨论】:

      • 我回家后会更好地格式化这个(在手机上发帖不是最简单的)
      猜你喜欢
      • 2014-11-10
      • 2020-08-12
      • 1970-01-01
      • 1970-01-01
      • 2012-12-17
      • 2015-07-05
      • 1970-01-01
      • 1970-01-01
      • 2018-11-29
      相关资源
      最近更新 更多