2009-05-20 7 views
2

私はperlスクリプトで次のコードを持っている:PerlのGetoptの::ロング関連の質問 - 相互排他コマンドライン引数

 

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

これらのundefは不要です。変数はundef値で始まります(配列やハッシュの場合は空です)。 –

答えて

4

私はGetopt :: Longでそれを行う方法はないと思っていますが、自分で実装するのは簡単です(私はあなたにどのように文字列を返す使用関数があると仮定しています)プログラムを呼び出すために:

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

なぜだけではなく、この:

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

0は有効なディレクトリ名で、 "0"は偽です。 –

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とは少し異なりますが、使用状況の概要を印刷している場合は、それをすべて行うことで重複を減らすのに役立ちます。ここで

は、私がdirまたはfilesはオプションが与えられたかに応じて値が含まれますsourceという隠しオプション、そう$opt->sourceを追加しました、そしてそれはあなたのため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と同じように、独自の変数を持つ各1の方法として含まれていることです。

関連する問題