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.





No Responses to “Perl Getopt and GetOptions”