Pergunta

O problema é que tenho n argumentos de linha de comando.Sempre haverá pelo menos 2, porém o número máximo é ilimitado.O primeiro argumento especifica um modo de operação e o segundo é um arquivo a ser processado.Do terceiro ao enésimo são as coisas a serem feitas no arquivo (que podem ser nenhuma, já que o usuário pode querer apenas limpar o arquivo, o que é feito se você passar apenas 2 argumentos).

Estou analisando os métodos disponíveis em Perl para trabalhar com matrizes, mas não tenho certeza de qual é a maneira "Perlish" de iterar do item 3 até o final da minha matriz.

Algumas opções que vi:

  • Pop do final da matriz até encontrar um elemento que não comece com "-" (já que o caminho do arquivo não começa com "-", embora eu suponha que poderia, o que pode causar problemas).
  • Mude a matriz duas vezes para remover os dois primeiros elementos.Tudo o que resta, posso simplesmente iterar, se o tamanho for pelo menos 1.

Gosto da segunda opção, mas não sei se é Perlish.E como estou tentando aprender Perl, é melhor aprender a maneira correta de fazer as coisas em Perl.

Foi útil?

Solução

Além de usar o módulo GETOpt como Sinan escreveu, eu provavelmente iria com:

my ( $operation, $file, @things ) = @ARGV;

E então você pode:

for my $thing_to_do ( @things ) {
...
}

Outras dicas

IMHO, a maneira perlish de realizar o que você precisa seria usar um dos Módulos Getopt no CPAN.

Se você ainda quiser fazer isso manualmente, eu iria para a segunda opção (é semelhante à maneira como lidamos com o primeiro argumento de uma chamada de método):

die "Must provide filename and operation\n" unless @ARGV >= 2;

my $op = shift @ARGV;
my $file = shift @ARGV;

if ( @ARGV ) {
    # handle the other arguments;
}

Eu poderia altamente recomendo usar Obteropt::Longo para analisar argumentos de linha de comando.É um módulo padrão, funciona muito bem e facilita exatamente o que você está tentando fazer.

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) {
    ...
}

Isso permite que você tenha um nome de opção longo e preencha automaticamente as informações em variáveis ​​para você, além de testá-las.Ele ainda permite adicionar comandos extras posteriormente, sem precisar fazer nenhuma análise extra dos argumentos, como adicionar uma opção de 'versão' ou 'ajuda':

# 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 } );

Então, você pode invocá-lo na linha de comando usando -, --, a primeira letra ou a opção inteira e GetOptions descobre tudo para você.Isso torna seu programa mais robusto e fácil de entender;é mais "adivinhável", você poderia dizer.A melhor parte é que você nunca precisa alterar o código que processa @ARGV, porque GetOptions cuidará de toda essa configuração para você.

A maneira mais padrão de fazer as coisas em Perl é através da CPAN.

Então minha primeira escolha seria GetOpt :: Long. Há também um tutorial sobre Devshed: Processando opções de linha de comando com Perl

Você pode usar um fatiar Para extrair o 2º. Para último itens, por exemplo:

[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:~]$ 

No entanto, você provavelmente deveria estar usando shift (ou até melhor, GetOpt::Long)

A resposta Deepesz é um bom caminho a percorrer.

Também não há nada de errado com sua segunda opção:

my $op     = shift; # implicit shift from @ARGV
my $file   = shift; 
my @things = @ARGV;

# iterate over @things;

Você também pode pular a cópia @ARGV em @things e trabalhar diretamente nele. No entanto, a menos que o script seja muito curto, muito simples e improvável que fique mais complexo ao longo do tempo, eu evitaria fazer muitos cortes.

Se você escolhe a abordagem de Deepsz ou esta é em grande parte uma questão de gosto.

Decidir o que é melhor é realmente uma questão de filosofia. O ponto crucial da questão é se você deve modificar globais como @ARGV. Alguns diriam que não é grande coisa, desde que seja feito de uma maneira altamente visível. Outros argumentariam a favor de sair @ARGV intocado.

Não preste atenção a ninguém discutindo a favor de uma opção ou de outra devido a problemas de velocidade ou memória. o @ARGV A matriz é limitada pela maioria das conchas a um tamanho muito pequeno e, portanto, nenhuma otimização significativa está disponível usando um método sobre o outro.

GetOpt :: Long, como foi mencionado também é uma excelente escolha.

Dê uma olhada Moosex :: getOpt Porque pode aguçar seu apetite por ainda mais coisas Moosey!.

Exemplo de 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

Produzirá o acima quando correr assim:

perl getopt.pl --Oper 1 -File File.txt --things Item1 --things Item2 -itens 3


Esses tipos de alces são verificados ... ./getopt --oper "not a number" produz:

Value "not a number" invalid for option oper (number expected)

E de graça, você sempre recebe uma lista de uso ;-)

usage: getopt.pl [long options...]
         --file         bit about file
         --oper         op doc stuff
         --things    

/I3az/

Para o caso mais geral com qualquer matriz:

for(my $i=2; $i<@array; $i++) {
    print "$array[$i]\n";
}

Isso percorre a matriz, começando com o terceiro elemento (índice 2). Obviamente, o exemplo específico que você especifica, a resposta de Depesz é a mais direta e melhor.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top