【问题标题】:How do I use Getopt::Long to parse arguments that may have spaces?如何使用 Getopt::Long 解析可能有空格的参数?
【发布时间】:2011-05-14 12:37:48
【问题描述】:

我有一个 shell 脚本,它输出如下一行:

prog_name -options ...

具体来说,举个例子:

prog_name -filter_arg +define BOOST +noconvtest +actuate-long -disp_arg +define size=40 res=30

请注意,上面没有引号,我无法控制修改 shell 脚本。 [但是,我不确定是否可以通过其他程序在上述语法中插入引号。]。

现在,我想将上面的内容发送到 Perl 程序来解析选项,以便它关联 +define BOOST +noconvtest +actuate-long 到选项 -filter_arg+define size=40 res=30 到选项 -disp_arg

有人可以帮我做吗?

【问题讨论】:

    标签: perl command-line-arguments


    【解决方案1】:

    我不是 100% 确定,但我认为您不能使用 GetOpt::Long 来执行此操作,至少不能直接使用。

    你需要我认为自己先通过,比如

    my @filters;
    my $filter = [];
    
    foreach (@ARGV) {
      if ($_ eq '+filter') {
        push @filters, $filter;
        $filter = [];
      } else {
        push @$filter, $_;
      }
    }
    push @filters, $filter if @$filter;
    
    foreach (@filters) {
      Getopt::Long::GetOptionsFromArray(@$_, ...
    
      ...
    }
    

    【讨论】:

    • 非常感谢 Axeman、David 和 Colin。非常感谢您的及时回复。并且本着 Perl 的真正精神,您已经展示了如何以多种方式解决问题!仔细阅读您的每个帖子,我学到了很多东西。热烈的问候。
    • 忽略了选项是由 shell 而非 Perl 分割的。
    【解决方案2】:

    你可以像这样传递回调:

    use strict;
    use warnings;
    use Getopt::Long;
    
    my $options = {};
    @ARGV=qw<-filter_arg +define BOOST +noconvtest +actuate-long -disp_arg +define size=40 res=30>;
    GetOptions( 
        $options # store in hash ref
        , qw<filter_arg define=s noconvtest actuate-long> 
        , disp_arg => sub { 
            # this will contain "+define size=40 res=30"
            $options->{disp_arg} = join( ' ', delete @ARGV[0..$#ARGV] );
          }
        );
    

    【讨论】:

      【解决方案3】:

      Getopt::Long 只是解析提供给 Perl 程序的@ARGV 列表。如果参数是@ARGV 列表中的单独条目,Getopt::Long 将以这种方式解析它们。您的问题是 shell 将每个参数作为单独的参数,因为它们周围没有引号。

      您的选择是在 Perl 脚本运行之前修改参数,或者修改 @ARGV 本身以将参数组合成它们应该包含的值。

      对于第一个选项,您可以使用sed 获取程序的输出并添加缺少的引号。如果你的程序总是吐出这样的字段:

      prog_name -filter_arg +define BOOST +noconvtest +actuate-long -disp_arg +define size=40 res=30
      

      您可以像这样通过sed 进行管道传输:

      $ orig_prog | sed -e 's/filter_arg /filter_arg "/' -e 's/ -disp_arg /" -disp_arg "/' -e 's/$/"/'
      

      或者这个:

      $ orig_prog | sed -e 's/^\(.*\) -filter_arg \(.*\) -disp_arg \(.*\)$/\1 -filter_arg "\2" -disp_arg "\3"/'
      

      这会在你的参数周围加上引号,它看起来像这样:

      prog_name -filter_arg "+define BOOST +noconvtest +actuate-long" -disp_arg "+define size=40 res=30"
      

      这样,@ARGV 将正确设置,因此GetOptions 函数将按照您希望的方式工作。

      另一种方法是在 Perl 程序运行后再调用 @ARGV,然后再调用 GetOptions

      my $value;
      my @newArgv;
      foreach my $param (@ARGV) {
         if ($param =~ /^-/) {
         if ($value) {
          push (@newArgv, $value);
          $value = "";
         }
         push(@newArgv, $param);
         } else {
         $value = $value ? "$value $param" : "$param";
         }
      }
      push (@newArgv, $value) if ($value);
      @ARGV = @newArgv;
      

      在上面的示例中,@ARGV 将具有以下值:

      @ARGV[0] = -filter_arg
      @ARGV[1] = +define BOOST +noconvtest +actuate-long
      @ARGV[2] = -disp_arg
      @ARGV[3] = +define size=40 res=30
      

      而且,Getopts::Long 现在应该按照您希望的方式工作。 附注:在较新版本的 Getopt::Long 中,您可以使用除 @ARGV 之外的其他数组。您只需将要用作第一个参数的数组放入GetOptions

      use Getopt::Long qw(GetOptionsFromArray);
      
      GetOptionsFromArray (
          \@newArgs,
          "filter_arg=s" => \$filter_arg,
          "disp_arg=s"   => \$disp_arg,
      );
      

      【讨论】:

        【解决方案4】:

        Getopt::Long 可以按原样解析你的命令行:

        my (@filter_arg, @display_arg);
        GetOptions('filter_arg=f{1,5}' => \@filter_arg, 'display_arg=i{1,5}' => \@display_arg);
        

        您将获得参数数组。

        请参阅Getopt::Long - Options with multiple values 以获得对已经可用的多值参数处理的更详细说明。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-06
          • 2016-11-15
          • 2010-11-06
          • 1970-01-01
          • 2023-03-07
          相关资源
          最近更新 更多