///Perl Getopt and GetOptions

Perl Getopt and GetOptions

Perl Getopt and GetOptions

Two Perl modules (Getopt and Getoptions::Long) work to extract program flags and arguments much like Getopt and Getoptsdo for shell programming. The Perl modules, especially GetOptions::Long, are much more powerful and flexible.

Simple scripts show the power of these:

#!/usr/bin/perl

# script is "./g"
use Getopt::Std;
%options=();
getopts("od:fF",\%options);
# like the shell getopt, "d:" means d takes an argument
print "-o $options{o}\n" if defined $options{o};
print "-d $options{d}\n" if defined $options{d};
print "-f $options{f}\n" if defined $options{f};
print "-F $options{F}\n" if defined $options{F};
print "Unprocessed by Getopt::Std:\n" if $ARGV[0];
foreach (@ARGV) {
print "$_\n";
}

Trying it out:

bash-2.05a$ ./g  -f -d F -o -F

-o 1
-d F
-f 1
-F 1
bash-2.05a$ ./g -o -d foo
-o 1
-d foo
bash-2.05a$ ./g -o rough -d foo
-o 1
Unprocessed by Getopt::Std:
rough
-d
foo

Processing of arguments stops when it saw “rough”.

If you leave off a required argument, it just gets swallowed:

bash-2.05a$ ./g -d

bash-2.05a$ ./g -d foo
-d foo

But it’s easily confused:

bash-2.05a$ ./g -d -o -f       

-d -o
-f 1

It thinks that -o is the argument of -d.

bash-2.05a$ ./g -k    

Unknown option: k

Like the simple shell “getopt”, this complains when it gets an option that it doesn’t know about. Unlike the shell “getopt”, prefacing the option string with a “:” doesn’t help. Instead, use “getopt”:

#!/usr/bin/perl

# we'll call this one ./gg
use Getopt::Std;
%options=();
getopt("odfF",\%options);
print "-o $options{o}\n" if defined $options{o};
print "-d $options{d}\n" if defined $options{d};
print "-f $options{f}\n" if defined $options{f};
print "-F $options{F}\n" if defined $options{F};

Note the lack of any “:”. This module doesn’t care which flags take values and which don’t: it assumes ALL of them take arguments.

The “getopt” isn’t very bright:

bash-2.05a$ ./gg -f -o -d foo 

-d foo
-f -o
bash-2.05a$ ./g -f -o -d foo
-o 1
-d foo
-f 1

But it doesn’t complain:

bash-2.05a$ ./gg -l

bash-2.05a$ ./g -l
Unknown option: l

Unlike their shell cousins, neither of these have any issues with arguments containing spaces:

bash-2.05a$ ./g -o  -d "foo bar"          

-o 1
-d foo bar
bash-2.05a$ ./gg -o "foo" -d "foo bar"
-o foo
-d foo bar

Far better than either of these is the Getopt::Long module. Here’s a script to play with it:

#!/usr/bin/perl

use Getopt::Long;
GetOptions("o"=>\$oflag,
"verbose!"=>\$verboseornoverbose,
"string=s"=>\$stringmandatory,
"optional:s",\$optionalstring,
"int=i"=> \$mandatoryinteger,
"optint:i"=> \$optionalinteger,
"float=f"=> \$mandatoryfloat,
"optfloat:f"=> \$optionalfloat);
print "oflag $oflag\n" if $oflag;
print "verboseornoverbose $verboseornoverbose\n" if $verboseornoverbose;
print "stringmandatory $stringmandatory\n" if $stringmandatory;
print "optionalstring $optionalstring\n" if $optionalstring;
print "mandatoryinteger $mandatoryinteger\n" if $mandatoryinteger;
print "optionalinteger $optionalinteger\n" if $optionalinteger;
print "mandatoryfloat $mandatoryfloat\n" if $mandatoryfloat;
print "optionalfloat $optionalfloat\n" if $optionalfloat;

print "Unprocessed by Getopt::Long\n" if $ARGV[0];
foreach (@ARGV) {
print "$_\n";
}

The hash array that this uses holds the argument name and the type of argument; what that points to is where it will store values for options processed.

Playing with it:

#

# doesn't care if it's -o or --o
bash-2.05a$ ./ggg -o
oflag 1
bash-2.05a$ ./ggg --o
oflag 1
#
# abbreviating is ok too
bash-2.05a$ ./ggg -verbose
verboseornoverbose 1
bash-2.05a$ ./ggg -verb
verboseornoverbose 1
#
# but not this
bash-2.05a$ ./ggg -verbosity
Unknown option: verbosity
#
# $verboseonoverbose will be 0 here
bash-2.05a$ ./ggg -noverb
#
# strings
bash-2.05a$ ./gggg -s
Option string requires an argument
bash-2.05a$ ./ggg -s=foo
stringmandatory foo
bash-2.05a$ ./ggg -optional
bash-2.05a$ ./ggg -optional=foo
optionalstring foo
#
# ambiguity
bash-2.05a$ ./ggg --opt
Option opt is ambiguous (optfloat, optint, optional)
#
# floats and integers
bash-2.05a$ ./ggg --optfloat=75.6
optionalfloat 75.6
bash-2.05a$ ./ggg --optint=75.6
Value "75.6" invalid for option optint (number expected)
bash-2.05a$ ./ggg --optint=75
optionalinteger 75
bash-2.05a$ ./ggg -f --optfloat=75.6 -o
Value "--optfloat=75.6" invalid for option float (real number expected)
oflag 1
# once it runs out of options, it leaves @ARGV alone:
bash-2.05a$ ./ggg -o foo bar
oflag 1

Unprocessed by Getopt::Long
foo
bar

GetOpt::Long is obviously much more flexible. The hash you pass is a little clumsy, but if you think about it, there’s no better way to do it. In some places, you might use something like this:

#!/usr/bin/perl

use Getopt::Long;
my %moo=();
GetOptions("o"=>\$moo{$oflag},
"verbose!"=>\$moo{verbose},
"string=s"=>\$moo{stringmandatory},
"optional:s"=>\$moo{optionalstring},
"int=i"=> \$moo{mandatoryinteger},
"optint:i"=> \$moo{optionalinteger},
"float=f"=> \$moo{mandatoryfloat},
"optfloat:f"=> \$moo{optionalfloat});

foreach (keys %moo) {
print "$_ = $moo{$_}\n";
}

print "Unprocessed by Getopt::Long\n" if $ARGV[0];
foreach (@ARGV) {
print "$_\n";
}

but if you have so many flags that you are thinking that is helpful, your program is surely trying much too hard to be all things to all people.

2010-05-26T11:28:33+00:00 April 22nd, 2005|CGI and Perl|0 Comments

About the Author:

Leave A Comment