2
Getopt::Long::Configure("no_pass_through");
my %opts = ();
GetOptions(\%opts,
           'opt1=s',
           'opt2=s',
           'opt3'
          );

test.pl bad_option_without_dash

How do I make getopts flag an error when a bad option is passed without a dash? I was expecting that no_pass_through will take care of this. What am I missing?

Jean
  • 21,665
  • 24
  • 69
  • 119
  • Look into [Getopt::Long](https://perldoc.perl.org/Getopt/Long.html) documentation, pay attention to first paragraph of description section -- you will figure out what you are missing. – Polar Bear Feb 07 '20 at 20:49

3 Answers3

3

Getopt::Long just extracts the options. It's up to you to validate the value of those options and the non-option arguments (which are left in @ARGV).

Specifically, if you want to make sure that only options have been passed, then you can use

@ARGV == 0
   or die("usage\n");

What I use:

use Getopt::Long qw( );

my ( $opt_opt1, $opt_opt2, $opt_opt3 );

sub parse_args {
   ( $opt_opt1, $opt_opt2, $opt_opt3 ) = ();

   Getopt::Long::Configure(qw( posix_default ));
   Getopt::Long::GetOptions(
      'help|h|?' => \&help,
      'opt1=s'   => \$opt_opt1,
      'opt2=s'   => \$opt_opt2,
      'opt3'     => \$opt_opt3,
   )
      or usage();

   # Validate $opt_* here if necessary.

   !@ARGV
      or usage("Too many arguments.");

   return @ARGV;
}

sub main {
   # my () = @_;   # This program doesn't accept non-option args.
   ...
}

main(parse_args());

Helpers:

use File::Basename qw( basename );

sub help {
   my $prog = basename($0);
   print
"Usage:
  $prog [options]
  $prog --help

Options:
  --opt1 FOO
      ...

  --opt2 BAR
      ...

  --opt3
      ...
";
   exit(0);
}

sub usage {
   if (@_) {
      my ($msg) = @_;
      chomp($msg);
      say STDERR $msg;
   }

   my $prog = basename($0);
   say STDERR "Try '$prog --help' for more information.";
   exit(1);
}
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Why is this sanity checking not part of implementation? i.e Don't allow stray options if `Getopt::Long::Configure("no_stray_options");` – Jean Feb 07 '20 at 23:26
  • There's no such thing as a stray option. The first value that's not part of an option (including the first value after `--`) and all subsequent values are the arguments for the program. There's no way for GetOptions to know how many arguments your program takes, nor does it makes sense to add a mechanism to tell it because that would be more complicated that making the check yourself (because some program expect a fix number of arguments, while some expect a closed-ended range, while some expect an open-ended range). – ikegami Feb 07 '20 at 23:48
  • lol. I wrote "it's opt to you" instead of "it's up to you". (Fixed) – ikegami Feb 07 '20 at 23:56
2

Getopt::Long operates only on options: arguments starting with hyphens. Without passthrough (no_pass_through is the default) it will remove them from @ARGV, leaving any non-option arguments for you to handle. If you expected no non-option arguments, you could determine that options were passed incorrectly if any arguments remain after calling GetOptions.

die "Usage: $0 [--opt1=string] [--opt2=string] [--opt3]\n" if @ARGV;

The return value of GetOptions is also useful, as it will indicate whether any unrecognized or invalid options were found.

GetOptions(...) or die "Usage: $0 ...\n";
Grinnz
  • 9,093
  • 11
  • 18
1

Options are denoted with a leading dash (hyphen); arguments are not.

You might find Getopt::Long Argument-callback useful:

A special option 'name' <> can be used to designate a subroutine to handle non-option arguments. When GetOptions() encounters an argument that does not look like an option, it will immediately call this subroutine and passes it one parameter: the argument name.

JRFerguson
  • 7,426
  • 2
  • 32
  • 36