J. Doe
J. Doe

Reputation: 91

Perl Getopt::Long - use subparameter only for defined parameter

I would like the --import parameter to have a "sub-parameter" that will only work on this parameter, nowhere else. Example:

app.pl --import --fresh

output: command working

app.pl --export

output: command working

app.pl --export --fresh

output: command not found

Can this be achieved by GetOpt::Long? Please, guide me a little.

Upvotes: 2

Views: 207

Answers (3)

zdim
zdim

Reputation: 66883

I take the purpose for this invocation, that matters for implementation here, to be the following.

There is a flag (call it $fresh) that need be set under the --import option, along with other flag(s) associated with --import. Additionally, there may be an independent option --fresh, which sets the $fresh flag.

While Getopt::Long doesn't support nested options this can be achieved using its other facilities. Set --import to take an optional argument with :, and set variables in a sub. If the word fresh is submitted as the value set the corresponding ($fresh) flag.

use warnings;
use strict;
use feature 'say';

use Getopt::Long;

my ($import, $fresh); 

GetOptions( 
    'import:s' => sub { 
        $import = 1;  
        $fresh  = 1 if $_[1] eq 'fresh';
    },
    'fresh!' => \$fresh   # if independent --fresh option is needed
);

say 'import: ', $import // 'not submitted';   #/
say 'fresh:  ', $fresh  // 'not submitted';

The sub receives two arguments, the option name and value, and the value is used to check whether fresh was passed. The code as it stands does nothing for other words that may be passed, but it can be made to abort (with a usage message) if any value other than fresh is submitted.

Whatever particular reasons there are to require this invocation can be coded in the sub.

If a separate --fresh option is indeed provided then the user need be careful since it is possible to submit conflicting values for $fresh – one with --import and another in --fresh itself. This can be checked for in the code.

The option --import still works as a simple flag on its own.

Valid invocations are

gol.pl --import         # $import is 1
gol.pl --import fresh   # $import is 1, $fresh is 1
gol.pl --fresh          # $fresh is 1

Since fresh is set in a sub as a value of --import it cannot be set with any other options.

This differs from the requirement by having fresh as a word, without dashes.

Upvotes: 2

ikegami
ikegami

Reputation: 385657

Options can indeed require a parameter. The parameter doesn't use --, though.

GetOptions(
   'help'     => \&help,
   'import:s' => \$opt_import,
)
   or usage();

defined($opt_import) && ( $opt_import eq '' || opt_import eq 'fresh' )
   or usage("Invalid value for --import");

@ARGV == 0
   or usage("Incorrect number of arguments");

# Convert into booleans for convenience.
$opt_fresh = defined($opt_import) && $opt_import eq 'fresh';
$opt_import = defined($opt_import);

The above accepts the following:

app.pl --import fresh
app.pl --import
app.pl

Note that using =s instead of :s will make providing a value mandatory.


Sample helpers:

use FIle::Basename qw( basename );

sub usage {
   my $basename = basename($0);
   print("usage: $basename [options]\n");
   print("       $basename --help\n");
   print("\n");
   print("Options:\n");
   print("\n");
   print("   --import [fresh]\n");
   exit(0);
}

sub usage {
   if (@_) {
      chomp( my $msg = shift );
      warn("$msg\n");
   }

   my $basename = basename($0);
   warn("Try '$basename --help' for more information.\n);
   exit(1);
}

Upvotes: 2

wolfrevokcats
wolfrevokcats

Reputation: 2100

I think that without resorting to partial parsing the closest you can get to with Getopt::Long is this:

use strict;
use warnings;
use Data::Dumper;
use Getopt::Long;

GetOptions('export=s%{1,5}'=>\my %export, 'another_option=s'=>\my $ao);

print Dumper({ 'export'=> \%export, 'another_option'=>$ao});

perl t1.pl  --export fresh=1 b=2 c=3 --another_option value

$VAR1 = {
          'export' => {
                        'c' => '3',
                        'b' => '2',
                        'fresh' => '1'
                      },
          'another_option' => 'value'
        };

Here export=s%{1,5} parses --export fresh=1 b=2 c=3 into hash %export.
s%{1,5} expects from 1 to 5 key=value pairs

Upvotes: 3

Related Questions