2009-05-20 3 views
2

У меня есть следующий код в моем сценарии PERL:Perl Getopt :: Long Относящегося Вопрос - Взаимно Эксклюзивные аргументы командной строки

 

my $directory; 
my @files; 
my $help; 
my $man; 
my $verbose; 

undef $directory; 
undef @files; 
undef $help; 
undef $man; 
undef $verbose; 

GetOptions(
      "dir=s" => \$directory, # optional variable with default value (false) 
      "files=s" => \@files, # optional variable that allows comma-separated 
           # list of file names as well as multiple 
        # occurrenceces of this option. 
      "help|?" => \$help,  # optional variable with default value (false) 
      "man" => \$man,   # optional variable with default value (false) 
      "verbose" => \$verbose # optional variable with default value (false) 
     ); 

    if (@files) { 
    @files = split(/,/,join(',', @files)); 
    } 

Каков наилучший способ справиться с взаимоисключающими аргументами командной строки? В моем сценарии я хочу, чтобы пользователь вводил только аргумент командной строки «--dir» или «--files», но не тот и другой. Есть ли способ настроить Getopt для этого?

Спасибо.

+2

Эти undefs не нужны, переменные начинаются с значения undef (или пустые в случае массивов и хэшей). –

ответ

4

Я не думаю, что есть способ в Getopt :: Должен сделать это, но его достаточно просто реализовать самостоятельно (я предполагаю, что есть функция использования, которая возвращает строку, которая сообщает пользователю, как для вызова программы):

die usage() if defined $directory and @files; 
2

Почему не только это:

if ($directory && @files) { 
    die "dir and files options are mutually exclusive\n"; 
} 
+1

Поскольку 0 является допустимым именем каталога, а «0» - false. –

2

Вы можете просто проверить наличие значений в обеих переменных.

if(@files && defined $directory) { 
    print STDERR "You must use either --dir or --files, but not both.\n"; 
    exit 1; 
} 

Или, если вы хотели бы просто игнорировать любые параметры, указанные после первого --dir или --files, вы можете указать как на функцию.

#!/usr/bin/perl 

use Getopt::Long; 

my $directory; 
my @files; 
my $mode; 
my $help; 
my $man; 
my $verbose; 

GetOptions(
    "dir=s" => \&entries, # optional variable with default value (false) 
    "files=s" => \&entries, # optional variable that allows comma-separated 
          # list of file names as well as multiple 
          # occurrences of this option. 
    "help|?" => \$help,  # optional variable with default value (false) 
    "man" => \$man,   # optional variable with default value (false) 
    "verbose" => \$verbose # optional variable with default value (false) 
); 

sub entries { 

    my($option, $value) = @_; 

    if(defined $mode && $mode ne $option) { 
     print STDERR "Ignoring \"--$option $value\" because --$mode already specified...\n"; 
    } 
    else { 
     $mode = $option unless(defined $mode); 
     if($mode eq "dir") { 
      $directory = $value; 
     } 
     elsif($mode eq "files") { 
      push @files, split(/,/, $value); 
     } 
    } 

    return; 

} 

print "Working on directory $directory...\n" if($mode eq "dir"); 
print "Working on files:\n" . join("\n", @files) . "\n" if($mode eq "files"); 
+0

Что делать, если каталог представляет собой строку «0»? Вам нужно проверить, не определено ли это, не верно ли это. –

+0

А, да. Виноват. –

+0

Где $ mode должен быть определен? –

0
use strict; 
use warnings; 
use Getopt::Long; 

my($directory,@files,$help,$man,$verbose); 

GetOptions(
    'dir=s' => sub { 
    my($sub_name,$str) = @_; 
    $directory = $str; 

    die "Specify only --dir or --files" if @files; 
    }, 

    # optional variable that allows comma-separated 
    # list of file names as well as multiple 
    # occurrences of this option. 
    'files=s' => sub { 
    my($sub_name,$str) = @_; 
    my @s = split ',', $str; 
    push @files, @s; 

    die "Specify only --dir or --files" if $directory; 
    },  

    "help|?" => \$help, 
    "man"  => \$man, 
    "verbose" => \$verbose, 
); 

use Pod::Usage; 
pod2usage(1) if $help; 
pod2usage(-exitstatus => 0, -verbose => 2) if $man; 
 
=head1 NAME 

sample - Using Getopt::Long and Pod::Usage 

=head1 SYNOPSIS 

sample [options] [file ...] 

Options: 
    -help   brief help message 
    -man    full documentation 

=head1 OPTIONS 

=over 8 

=item B 

Print a brief help message and exits. 

=item B 

Prints the manual page and exits. 

=back 

=head1 DESCRIPTION 

B will read the given input file(s) and do something 
useful with the contents thereof. 

=cut 
0

Вы можете сделать это с Getopt::Long::Descriptive. Это немного отличается от Getopt::Long, но если вы печатаете резюме использования, это помогает уменьшить дублирование, выполняя все это для вас.

Здесь я добавил скрытый вариант называется source, так $opt->source, который будет содержать значение dir или files в зависимости от того, какой вариант был дан, и он будет следить за соблюдением one_of ограничение для вас. Указанные значения будут в $opt->dir или $opt->files, в зависимости от того, что было дано.

my ($opt, $usage) = describe_options(
    '%c %o', 
    [ "source" => hidden => { 
     'one_of' => [ 
      [ "dir=s" => "Directory" ], 
      [ "[email protected]" => "FilesComma-separated list of files" ], 
     ] 
    } ], 
    [ "man" => "..." ],   # optional variable with default value (false) 
    [ "verbose" => "Provide more output" ], # optional variable with default value (false) 
    [], 
    [ 'help|?' => "Print usage message and exit" ], 
); 
print($usage->text), exit if ($opt->help); 

if ($opt->files) { 
    @files = split(/,/,join(',', @{$opt->files})); 
} 

Основное отличие для остальной части вашего сценария является то, что все параметры содержатся в способах $opt переменной, а не каждый из которых имеет свою собственную переменную, как с Getopt::Long.

Смежные вопросы