Если Вы хотите что-то, что даст Вам различную метрику программного обеспечения (сложность и т.д.) для Вашего кода затем, я настоятельно рекомендую SourceMonitor от Campswood Software . Это работает на C и C++ также, и это свободно.
Помимо использования модуля Getopt, как писал Синан, я бы, вероятно, пойти с:
my ( $operation, $file, @things ) = @ARGV;
А затем вы можете:
for my $thing_to_do ( @things ) {
...
}
IMHO, способ Perlish для выполнения того, что вам нужно, - это использовать один из модулей Getopt на CPAN .
Если вы все еще хотите сделать это вручную , Я бы выбрал второй вариант (это похоже на то, как мы обрабатываем первый аргумент вызова метода):
die "Must provide filename and operation\n" unless @ARGV >= 2;
my $op = shift @ARGV;
my $file = shift @ARGV;
if ( @ARGV ) {
# handle the other arguments;
}
Я бы настоятельно рекомендовал использовать Getopt :: Long для анализа аргументов командной строки. Это стандартный модуль, он отлично работает и делает именно то, что вы пытаетесь сделать, с легкостью.
use strict;
use warnings;
use Getopt::Long;
my $first_option = undef;
my $second_option = undef;
GetOptions ('first-option=s' => \$first_option,
'second-option=s' => \$second_option);
die "Didn't pass in first-option, must be xxxyyyzzz."
if ! defined $first_option;
die "Didn't pass in second-option, must be aaabbbccc."
if ! defined $second_option;
foreach my $arg (@ARGV) {
...
}
Это позволяет вам иметь длинное имя параметра и автоматически подставлять информацию в переменные для вас, и позволяет вам тестировать Это. Он даже позволяет вам добавлять дополнительные команды позже, без необходимости выполнять дополнительный анализ аргументов, например, добавляя параметр «версия» или «справка»:
# adding these to the above example...
my $VERSION = '1.000';
sub print_help { ... }
# ...and replacing the previous GetOptions with this...
GetOptions ('first-option=s' => \$first_option,
'second-option=s' => \$second_option)
'version' => sub { print "Running version $VERSION"; exit 1 },
'help' => sub { print_help(); exit 2 } );
Затем вы можете вызвать его из командной строки, используя -
, -
, первая буква или весь параметр, а GetOptions
все расскажет за вас. Это делает вашу программу более надежной и легкой для понимания; Вы могли бы сказать, что это более "предположительно".
Вы можете использовать срез для извлечения второго. до последних элементов, например:
[dsm@localhost:~]$ perl -le 'print join ", ", @ARGV[2..$#ARGV];' 1 2 3 4 5 6 7 8 9 10 00
3, 4, 5, 6, 7, 8, 9, 10, 00
[dsm@localhost:~]$
однако вам, вероятно, следует использовать shift
(или даже лучше, GetOpt :: Long
)
Самый стандартный способ делать что-то в Perl - через CPAN.
Так что мой первый выбор будет Getopt :: Лонг . Также есть руководство по DevShed: Обработка параметров командной строки с помощью Perl
ответ deepesz - один из хороших вариантов.
Также нет ничего плохого в вашем втором варианте:
my $op = shift; # implicit shift from @ARGV
my $file = shift;
my @things = @ARGV;
# iterate over @things;
Вы также можете пропустить копирование @ARGV
в @things
и работать непосредственно с ним. Однако, если сценарий не будет очень коротким, очень простым и вряд ли станет более сложным со временем, я бы не стал слишком много сокращать.
Выберете ли вы подход deepesz или этот, в значительной степени дело вкуса.
. Решение, что лучше, на самом деле вопрос философии. Суть проблемы в том, следует ли вам изменять глобальные переменные, такие как @ARGV
. Кто-то скажет, что в этом нет ничего страшного, если это делается на видном месте. Другие будут возражать, чтобы оставить @ARGV
нетронутым.
Не обращайте внимания на тех, кто выступает за тот или иной вариант из-за проблем со скоростью или памятью. Массив @ARGV
ограничен большинством оболочек до очень небольшого размера, и, таким образом, при использовании одного метода по сравнению с другим не возможна значительная оптимизация.
Getopt :: Long , как уже упоминалось. тоже отличный выбор.
Не обращайте внимания на тех, кто выступает за тот или иной вариант из-за проблем со скоростью или памятью. Массив @ARGV
ограничен большинством оболочек до очень небольшого размера, и, таким образом, при использовании одного метода по сравнению с другим не возможна значительная оптимизация.
Getopt :: Long , как уже упоминалось. тоже отличный выбор.
Не обращайте внимания на тех, кто выступает за тот или иной вариант из-за проблем со скоростью или памятью. Массив @ARGV
ограничен большинством оболочек до очень небольшого размера, и, таким образом, при использовании одного метода по сравнению с другим не возможна существенная оптимизация.
Getopt :: Long , как уже упоминалось. тоже отличный выбор.
Взгляните на MooseX :: Getopt , потому что он может возбудить ваш аппетит к еще большему Moosey! .
Пример MooseX :: Getopt:
# getopt.pl
{
package MyOptions;
use Moose;
with 'MooseX::Getopt';
has oper => ( is => 'rw', isa => 'Int', documentation => 'op doc stuff' );
has file => ( is => 'rw', isa => 'Str', documentation => 'about file' );
has things => ( is => 'rw', isa => 'ArrayRef', default => sub {[]} );
no Moose;
}
my $app = MyOptions->new_with_options;
for my $thing (@{ $app->things }) {
print $app->file, " : ", $thing, "\n";
}
# => file.txt : item1
# => file.txt : item2
# => file.txt : item3
Произойдет указанное выше при запуске следующим образом:
perl getopt.pl --oper 1 --file file.txt --things item1 --things item2 --things item3
Эти Moose типы проверяются ... ./ getopt --oper "not a number"
выдает:
Value "not a number" invalid for option oper (number expected)
И бесплатно вы всегда получаете список использования; -)
usage: getopt.pl [long options...] --file bit about file --oper op doc stuff --things
/ I3az /
Для более общего случая с любым массивом:
for(my $i=2; $i<@array; $i++) {
print "$array[$i]\n";
}
Этот цикл проходит по массиву, начиная с третьего элемента (индекс 2). Очевидно, что конкретный пример, который вы указали, ответ depesz является наиболее простым и лучшим.