我有一个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
。
有人可以帮我这样做吗?
答案 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以获取有关已经可用的多值参数处理的更详细说明。