HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Parsing command line arguments in Perl

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
argumentslineperlparsingcommand

Problem

I use this idiom to parse command line arguments in Perl:

my @args;
my $encode = 1;

while (@ARGV) {
    for (shift(@ARGV)) {
        ($_ eq '-h' || $_ eq '--help') && do { &usage(); };
        # ... more options here
        ($_ eq '--') && do { push(@args, @ARGV); undef @ARGV; last; };
        ($_ =~ m/^-.+/) && do { print "Unknown option: $_\n"; &usage(); };
        push(@args, $_);
    }
}


This let's me do things like:

  • Supports command line arguments in arbitrary order



  • Supports using -- to use any following arguments "as is", without parsing



  • Stop parsing and print usage message on -h, or --help



  • Raise error if a -something flag is detected that is not matched by any of the parsing rules



Here's a short example script using this idiom:

#!/usr/bin/env perl

use strict;
use warnings;

&usage() unless @ARGV;

my @args;
my $encode = 1;

while (@ARGV) {
    for (shift(@ARGV)) {
        ($_ eq '-h' || $_ eq '--help') && do { &usage(); };
        ($_ eq '-D' || $_ eq '--decode') && do { $encode = ! $encode; last; };
        ($_ eq '--') && do { push(@args, @ARGV); undef @ARGV; last; };
        ($_ =~ m/^-.+/) && do { print "Unknown option: $_\n"; &usage(); };
        push(@args, $_);
    }
}

sub usage {
    $0 =~ m|[^/]+$|;
    print "Usage: %%CODEBLOCK_1%%amp; [-h|--help] [-D|--decode]\n";
    print "\n";
    print "Encode (= default) or decode Base64\n";
    exit 1;
}

use MIME::Base64;
if ($encode) {
    print map(&MIME::Base64::encode_base64($_), @args);
} else {
    print map(&MIME::Base64::decode_base64($_), @args);
}


Is this a good technique for parsing command line arguments in Perl?
Is there a better way?

I'm also interested in improvement ideas about the short script itself too.

Solution

There are several modules on CPAN that are made for this task. They all reside in the Getopt namespace. Getopt::Long even comes with the standard distribution. So coming to your question: Yes, there are better ways.

If you are interested in something more fancy, you could have a look at Getopt::Declare where you can write the usage page and fill your variables in the same place. It has a downside, though since it introduces another DSL.

What I definitely would recommend is that you take a look at <<HERE docs for printing longer texts. Some people dislike them,because of their strange syntactic properties, but they are the usual way to express multiline strings in perl.

Context

StackExchange Code Review Q#64753, answer score: 9

Revisions (0)

No revisions yet.