Как использовать Getopt :: Long для анализа аргументов, которые могут иметь пробелы? - PullRequest
2 голосов
/ 23 ноября 2010

У меня есть сценарий оболочки, который выдает строку следующим образом:

prog_name -options ...

Чтобы быть конкретным, например:

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

Обратите вниманиечто выше нет кавычек, и я не имею права изменять скрипт оболочки.[Однако я не уверен, смогу ли я вставить кавычки в вышеприведенный синтаксис с помощью какой-либо другой программы.]1011 * для опции -filter_arg и +define size=40 res=30 для опции -disp_arg.

Может кто-нибудь, пожалуйста, помогите мне сделать это?

Ответы [ 4 ]

5 голосов
/ 23 ноября 2010

Getopt::Long просто анализирует список @ARGV, предоставленный программе Perl.Если параметры являются отдельными записями в списке @ARGV, Getopt::Long проанализирует их таким образом.Ваша проблема в том, что оболочка помещает каждый аргумент в качестве отдельного параметра, так как вокруг них нет кавычек.

Вы можете либо изменить параметры перед запуском скрипта 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 будет работать так, как вы хотите

Другой способ - выполнить munge @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,
);
2 голосов
/ 23 ноября 2010

Вы можете передать обратный вызов следующим образом:

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] );
      }
    );
0 голосов
/ 30 июля 2012

Getopt :: Long может анализировать вашу командную строку как:

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

Вы получите массивы пармов.

См. Getopt :: Long - Опции с несколькими значениями для более подробного объяснения обработки многозначных параметров, которая уже доступна.

0 голосов
/ 23 ноября 2010

Я не уверен на 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(@$_, ...

  ...
}
...