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.
If you found this post useful you may also want to check these out:
