Search code examples
perlgetopt-long

How can I handle an option made of an arbitrary number with Getopt::Long[::Descriptive]?


I would like to be able to handle options like -1 or -10 similarly to how head or -tail do.

In other words, be able to do

my_script.pl -10 --some-other-option arguments

and be able to retain the value of the -10 option.

Right now the only idea that works is processing the command line before it is fed to describe_options like so:

my ($count) = map { /\-(\d+)/; $1 } grep { /^\-(\d+)$/ } reverse @ARGV;
@ARGV = grep { !/^\-\d+$/ } @ARGV;

my ($opt, $usage) = describe_options(...)

but it looks clunky, and the option doesn't pop up in $usage.

Is there a better way? Answers using Getopt::Long will work too - I can adapt them to GetOpt::Long::Descriptive


Solution

  • Getopt::Long (Not sure about Getopt::Long::Descriptive) can be configured to call a user-supplied function on unknown arguments; this can be used to handle such cases.

    Example:

    #!/usr/bin/env perl
    use strict;
    use warnings;
    use feature qw/say/;
    # :config required to enable handling of "<>" psuedo-option
    use Getopt::Long qw/:config pass_through/;
    use Scalar::Util qw/looks_like_number/;
    
    my $verbose = 0;
    my $lines = 10;
    GetOptions("verbose" => \$verbose,
               "<>" => \&parse_lines)
        or die "Unable to parse options.\n";
    say "Lines is $lines";
    
    sub parse_lines {
        my $arg = shift;
        if (looks_like_number $arg) {        
            $lines = $arg =~ s/^-//r; # Turn -X into X
        } else {
            die "Invalid option '$arg'\n";
        }
    }
    

    And usage:

    $ perl foo.pl -123
    Lines is 123
    $ perl foo.pl --bar
    Invalid option '--bar'
    Unable to parse options.