Perl Getopt :: Long Related Question - Mutual exclusive command line arguments

I have the following code in my perl script:

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

What is the best way to handle mutually exclusive command line arguments? In my script, I want the user to enter only the command line argument "--dir" or "--files", but not both. Is there a way to configure Getopt for this?

Thanks.

+2
source share
5 answers

I donโ€™t think there is a way in Getopt :: Long to do this, but it is quite simple to implement it yourself (I assume there is a use function that returns a string that tells the user how to call the program):

die usage() if defined $directory and @files; 
+4
source

Why not just:

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

You can simply check for values โ€‹โ€‹in both variables.

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

Or, if you just want to ignore any parameters specified after the first --dir or -files, you can specify both in the function.

 #!/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"); 
+2
source
 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
source

You can do this with Getopt::Long::Descriptive . This is slightly different from Getopt::Long , but if you print a usage summary, it helps reduce duplication by doing all this for you.

Here I added a hidden source option, so $opt->source , which will contain the value dir or files depending on which option was provided, will force the one_of constraint on you. The specified values โ€‹โ€‹will be in $opt->dir or $opt->files , depending on what was specified.

 my ( $opt, $usage ) = describe_options( '%c %o', [ "source" => hidden => { 'one_of' => [ [ "dir=s" => "Directory" ], [ " files=s@ " => "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})); } 

The main difference for the rest of your script is that all parameters are contained as methods of the $opt variable, and not each of them has its own variable, for example, using Getopt::Long .

0
source

All Articles