如何使用Getopt :: Long来解析可能包含空格的参数?

时间:2010-11-23 14:56:53

标签: perl command-line-arguments

我有一个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

有人可以帮我这样做吗?

4 个答案:

答案 0 :(得分:5)

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功能将按照您希望的方式运行。

另一种方法是在你调用@ARGV之前运行Perl程序后进行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,
);

答案 1 :(得分: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] );
      }
    );

答案 2 :(得分:0)

我不是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(@$_, ...

  ...
}

答案 3 :(得分:0)

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以获取有关已经可用的多值参数处理的更详细说明。