About this mini-article series. Each day for 24 days, I will be reviewing a module that parses command-line options (such module is usually under the Getopt::* namespace). First article is here.
Receiving options from command-line arguments is usually just one of a few ways a CLI program gets its input. Two of the other most popular ways are: environment variables (e.g. PERL_CPANM_OPT or perl's own PERL5OPT) and configuration files (e.g. /etc/wgetrc or dzil.ini). These alternative ways are used when command-line arguments are less appropriate, e.g. when there are lots of options which would make inputting them all to command-line arguments cumbersome or tedious. Another case is when the option contains something sensitive like login name/password, which when specified via command-line makes it easily peekable by other users via a simple `ps ax`.
Environment variables with name like FOO_OPT usually just extend the command-line arguments. You can put command-line options here like you would into command-line arguments. If you use configuration files there's the additional issue of what format to write the configuration in, and which locations to search the configuration files in. A simple choice is to also assume the configuration files to contain just a bunch of command-line options, separable by newlines. This way, you don't have to invent a new format or create additional mapping between configuration parameters and command-line options. This method is used by various programs large and small, such as: curl, or mplayer and mpv.
Getopt::ArgvFile is a module first released by Jochen Stenzel (JSTENZEL) in 1999 (but the copyright message hints that it was first written in 1993). Last update is in 2007. It currently has 20 CPAN distributions depending on it, and looks like Barbie (BARBIE) and Kathryn Andersen (RUBYKAT) are two of its prominent users. The module seems to be well received by the community, if judging from its CPAN Ratings reviews.
As previously stated, this module is not an option parsing module or a Getopt::Long wrapper, but its companion instead. To use it, you put:
use Getopt::Long; GetOptions(...);
This will make Getopt::ArgvFile scan for @-prefixed arguments like @myapp.conf
in command-line arguments and put the command-line options found in the contents of myapp.conf file into @ARGV. By the time GetOptions() is run, it sees the command-line options from the config file myapp.conf already inserted into @ARGV. Example, if myapp.conf contains:
# a comment
Then this command-line arguments:
% myapp @myapp.conf –opt1 quux –no-opt4
will produce this @ARGV:
["--opt1=foo", "--opt2=bar", "--opt3=baz", "--opt3", "qux", "--opt1", "quux", "--no-opt4"]
The config file can contain shell-style comment (# blah) or even POD. It can contain another @file to include other files.
Since the @file syntax is not commonly used, you can also configure Getopt::ArgvFile to scan for a special option to specify config file instead (like –config, as commonly used by many programs).
Getopt::ArgvFile can also be instructed to look for config files in some common locations like the script's path (using import option default => 1), home directory (home => 1), or current directory (current => 1). The config file name can be configured too, with multiple names if necessary.
In short, Getopt::ArgvFile is a quick and convenient way to add config file reading support to your application, but the following are some comments about the module:
First, when a specified config file cannot be read (permission denied, etc), there is no warning or error message whatsoever. This is my main complaint.
There is no equivalent for –no-config special option to disable config file reading. Adding this option to GetOptions is also problematic, as Getopt::ArgvFile works before Getopt::Long. But if you use autohelp/autousage like Getopt::Long::Descriptive, you might want to add –config and –no-config too so they are documented.
The separated two-step approach also comes with its problem. For example, if you specify a command-line option –foo @bar, wanting the foo option to contain the value @bar, you can't because @bar will already have been stripped by Getopt::ArgvFile.
The default settings show the module's age. Finding config files in script path (default => 1) or current directory (current => 1) is not considered proper nowadays. There is also currently no way to disable parsing of – and +
option prefixes (like -config or +config) by Getopt::ArgvFile, although this can be implemented pretty trivially, e.g. by looking at Getopt::Long's configuration (but this requires Getopt::Long to be loaded first).
All these considerations make me prefer something more integrated, like Perinci::CmdLine or App::Options (although those two modules happen to use configuration files in INI/INI-like format instead of raw command-line options).