Question

I have a script which does some basic awk like filtering using a while(<>) loop. I want the script to be able to display usage and version, but otherwise assume all arguments are files. How do I combine getopt with the <> operator?

Was it helpful?

Solution 3

As others have mentioned, Getopt::Long is the prefered module. It has been around since Perl 3.x.

There's a lot of options, and it can take a while to get use to the syntax, but it does exactly what you want:

use strict;
use warnings;
use Getopt::Long;
use feature qw(say);
use Pod::Usage;

my ( $version, $help );   #Strict, we have to predeclare these:

GetOptions(
   'help'    => \$help,
   'version' => \$version,
) or pod2usage ( -message => "Invalid options" );

That's all there is to it. When the Getoptions subroutine runs, it will parse your command line (the @ARGV array) for anything that starts with a - or --. It will process those, and when it comes to either a double dash by itself, or an option not starting with a dash, it will assume those are files and it's done processing. At that point, all of the option strings (and their parameters) have been shifted out of the @ARGSV array, and you're left with your files:

if ( $help ) {
    pod2usage;
}
if ( $version ) {
    say "Version 1.23.3";
    exit;
}

while ( my $file = <>) {
    ...
}

Getopts::Long is part of the standard Perl installation, so it should always be available to you.

I know many people are wary of using these modules because they think they're not standard Perl, but they are just as much a part of Perl as commands like print and chomp. Perl comes with over 500 of them and they're yours to use.

OTHER TIPS

Getopt plays nicely with @ARGV. Example

use strict; use warnings;
use feature 'say';
use Getopt::Long;

GetOptions 'foo=s' => \my $foo;

say "foo=$foo";
say "ARGV:";
say for @ARGV;

Then:

$ perl test.pl --foo fooval --bar
Unknown option: bar
foo=fooval
ARGV:
$ perl test.pl --foo fooval bar
foo=fooval
ARGV:
bar
$ perl test.pl --foo fooval -- --bar
foo=fooval
ARGV:
--bar

Summary:

  • Any items in @ARGV after the switches are simply left there.
  • This works as expected for normal filenames (that don't start with a hyphen-minus).
  • You can always use a -- to abort parsing of switches.

This works as expected for me.

use warnings;
use strict;
use Getopt::Long qw(GetOptions);

my %opt;
GetOptions(\%opt, qw(help)) or die;

die 'usage' if $opt{help};

while (<>) {
    print;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top