Как предоставить больше аргументов (разделенных пробелом) для одной опции в Getopt :: Std в perl? - PullRequest
1 голос
/ 01 августа 2020

Я хотел бы указать больше аргументов для одного варианта:

#!/usr/bin/perl -w
use Getopt::Std qw[getopts];

getopts('a:');

if($opt_a){
    print "$opt_a\n";
}

и использовать его как

$ foo.pl -a foo bar #...

и получить каждый указанный файл / аргумент в массив в @opt_a, это возможно?

Ответы [ 2 ]

2 голосов
/ 01 августа 2020

Очевидно, это невозможно с Getopt::Std. Но Getopt::Long имеет экспериментальную функцию , которая, кажется, предоставляет то, что вы хотите.

#!/usr/bin/perl

use strict;
use warnings;

use Getopt::Long;

my @args_a;

GetOptions('a=s{1,}' => \@args_a);

foreach my $arg_a (@args_a) {
  print("$arg_a\n");
}

Когда вышеуказанное вызывается с помощью -a x y z, то @args_a = ('x', 'y', 'z').

Но, как указал ikegami, вы должны найти способ различать guish параметров без флага (если вы намереваетесь иметь такие). Вы можете использовать --, чтобы разделить их. Вызов с -a x y z -- n m o приведет к @args_a = ('x', 'y', 'z') и @ARGV = ('n', 'm', 'o').

И, конечно же, есть риск написать программу, основанную на экспериментальной функции, которая может быть удалена в более поздних версиях.

Альтернативой, которая не полагается на экспериментальную функцию (но все же требует Getopt::Long), было бы разрешить несколько -a s.

...
GetOptions('a=s' => \@args_a);
...

будет делать это. Здесь, чтобы получить @args_a = ('x', 'y', 'z'), вызов должен быть с -a x -a y -a z.

2 голосов
/ 01 августа 2020

Забудьте на секунду о Getopt :: Std. Как модуль (или любой другой код) узнает, что bar было значением a, а не первым позиционным аргументом? Без средств для этого ваша грамматика будет неоднозначной, и для нее невозможно написать синтаксический анализатор.

Это можно решить одним из трех способов. (Ну, наверняка есть и другие.)

Решение 1 Разрешить повторение параметра и флага.

prog -a foo -a bar pos0 pos1
use Getopt::Long qw( GetOptions );

GetOptions(
   '?|h|help' => \&help,
   'a=s'      => \my @opt_a,
)
   or usage();

Решение 2 Используйте -a, чтобы указать, что означают позиционные аргументы.

prog -a foo bar
use Getopt::Long qw( GetOptions );

GetOptions(
   '?|h|help' => \&help,
   'a'        => \my @opt_a,
   'b'        => \my $opt_b,
)
   or usage();

( $opt_a ? 1 : 0 ) + ( $opt_b ? 1 : 0 ) == 1
   or usage("-a or -b must be specified, but not both");

my $opt_action = $opt_a ? 'a' : 'b';

@ARGV > 0
   or usage("Invalid number of arguments");

Решение 3 Предположим, что все значения, следующие за -a, принадлежат -a

Оказывается, есть стандартный способ обозначить начало позиционных аргументов. Использование -- будет отличать guish значения параметров от позиционных аргументов.

prog -a foo bar -- pos0 pos1
use Getopt::Long qw( GetOptions );

GetOptions(
   '?|h|help' => \&help,
   'a=s{1,}'  => \my @opt_a,
)
   or usage();

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

Это также подвержено ошибкам. У людей возникнет искушение сделать следующее:

prog -a foo pos0    # XXX Doesn't work as expected!

Примечания:

  1. Я использовал Getopt :: Long. Если Getopt :: Std тоже может это сделать, отлично. Я использовал то, что знал.
  2. См. this для примера реализации help и usage.
...