Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?

Force Getopt::Long to Require ONLY Equals Sign Between Option Name and Value

by roho (Canon)
on Oct 18, 2019 at 20:36 UTC ( #11107671=perlquestion: print w/replies, xml ) Need Help??

roho has asked for the wisdom of the Perl Monks concerning the following question:

Here is what I am trying to do. I have a command line option that is defined in Getopt::Long as having an optional string value as follows:

use Getopt::Long; GetOptions( "ot:s" => \$ot ) or die("Error in command line arguments\n +");

The problem occurs when -ot (without a value) is followed by either another option or a program argument. The -ot option will take the next word as its value.

I know I can signal the end of options by using -- on the command line, but for backward compatibility before this program used Getopt::Long (the program previously used "/usr/bin/perl -s" to process command line options), I would like to tell Getopt::Long to always require an equals sign before a value so that -ot (without a value) can be followed by a program argument without the invervening -- in the command line.

Here is what I am aiming for:

Scenario #1: -ot=123 arg1 arg2 ...

This works fine. Variable $ot='123'

Scenario #2: -ot arg1 arg2 ...

I need $ot to be set to the empty string '' instead of 'arg1', without the need of an intervening -- on the command line (hence the need to force Getopt::Long to require an equals sign between the option name and its value).

Again, my goal is backward compatibility with the way this program was called before adding Getopt::Long, because this program is very central to the system and is literally called in thousands of places. TIA for any suggestions.

"It's not how hard you work, it's how much you get done."

Replies are listed 'Best First'.
Re: Force Getopt::Long to Require ONLY Equals Sign Between Option Name and Value
by haukex (Chancellor) on Oct 19, 2019 at 08:50 UTC

    I also don't see a way to do that via configuration options at the moment. But @ARGV is just an array of strings, so you could just do e.g. "s/^-ot\K$/=/ for @ARGV;" before the GetOptions call:

    use warnings; use strict; use Getopt::Long qw/ GetOptionsFromArray /; use Test::More tests => 6; my @argv1 = qw/ -ot=123 arg1 arg2 /; s/^-ot\K$/=/ for @argv1; is_deeply \@argv1, ["-ot=123", "arg1", "arg2"]; GetOptionsFromArray(\@argv1, \my %opts1, "ot:s") or die; is_deeply \%opts1, { ot => 123 }; is_deeply \@argv1, ["arg1", "arg2"]; my @argv2 = qw/ -ot arg1 arg2 /; s/^-ot\K$/=/ for @argv2; is_deeply \@argv2, ["-ot=", "arg1", "arg2"]; GetOptionsFromArray(\@argv2, \my %opts2, "ot:s") or die; is_deeply \%opts2, { ot => "" }; is_deeply \@argv2, ["arg1", "arg2"];

    Update: Switched from Data::Dump to Test::More.

      Thank you all for your replies. I am going with the suggestion from haukex. That approach meets my current need and keeps me moving forward.
      I will ask the author of Getopt::Long if a configuration option can be added to the module to accomplish this in the future. Thanks again.

      "It's not how hard you work, it's how much you get done."

Re: Force Getopt::Long to Require ONLY Equals Sign Between Option Name and Value
by tangent (Vicar) on Oct 19, 2019 at 00:04 UTC
    Getopt::Long has a configration option called 'gnu_compat' which I thought might work, but...

    gnu_compat controls whether --opt= is allowed, and what it should do. Without gnu_compat, --opt= gives an error. With gnu_compat, --opt= will give option opt and empty value. This is the way GNU getopt_long() does it.

    Note that --opt value is still accepted, even though GNU getopt_long() doesn't.

    Your problem is that note at the end. You do not want "--opt value" to be accepted, you want it to behave like "--opt= nextarg".

    In the source for Getopt::Long there is this code to handle gnu_compat:

    # Check if there is an option argument available. if ( $gnu_compat ) { my $optargtype = 0; # none, 1 = empty, 2 = nonempty, 3 = aux --cut-- elsif ( defined $rest || @$argv > 0 ) { # GNU getopt_long() does not accept the (optional) # argument to be passed to the option without = sign. # We do, since not doing so breaks existing scripts. $optargtype = 3; } --cut-- return (1, $opt, $ctl, $type eq 's' ? '' : 0) if $optargtype == 1; # --foo= -> return nothing }
    I think if you set '$optargtype' to 1 here it would work.

    Maybe Getopt::Long could add a configuration option called 'gnu_compat_strict' so you could have:

    elsif ( defined $rest || @$argv > 0 ) { $optargtype = $gnu_compat_strict ? 1 : 3; }
Re: Force Getopt::Long to Require ONLY Equals Sign Between Option Name and Value
by clueless newbie (Deacon) on Oct 18, 2019 at 20:56 UTC

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://11107671]
Approved by jcb
Front-paged by jcb
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (4)
As of 2019-12-07 09:42 GMT
Find Nodes?
    Voting Booth?
    Strict and warnings: which comes first?

    Results (160 votes). Check out past polls.