Java Command-line Argument HandlingAndrew S. Townley 08-Jun-2003
This is the original article provided with the 2.0-Beta2
release. It is still relevant for background information and
how to do "classic" command-line argument handling, but
it does not reflect the current way the library should be
used. Please bear this in mind when reading the article.
[Ed.]
This example is lifted from the documentation for the com.townleyenterprises.command package. The example illustrates the majority of the features present in the library including:
Step 1: Import the required classes (normally, you wouldn't just import everything). import java.util.*; import com.townleyenterprises.command.*;
Step 2: Define a
It is important to note that for the custom option to have
the expected behavior later in the program, the parent class
must be given the chance to recognize that the option has
been matched. This is done by calling
This step (or something similar) is only required if the
default behavior of the class RepeatableOption extends CommandOption { RepeatableOption(String longName, char shortName, String argHelp, String argDesc) { super(longName, shortName, true, argHelp, argDesc); } public void optionMatched(String arg) { super.optionMatched(arg); _args.add(arg); } List getArgs() { return _args; } ArrayList _args = new ArrayList(); }
Step 3: Provide a class that implements the
In this case, three options are defined (all of which have both short and long forms). The parameters for creating the options are very similar to the Red Hat popt library which was a big influence on the behavior of the package. They include:
The options could be created as anonymous object instances, but then it would require additional programmer effort to ensure that they were correctly handled. For more information on this topic, please refer to the package documentation. public class feather implements CommandListener { static CommandOption create = new CommandOption("create", 'c', false, null, "Create a new archive."); static CommandOption file = new CommandOption("file", 'f', true, "<filename>", "Specify the name of the archive" + " (default is stdout)."); static RepeatableOption xclude = new RepeatableOption("exclude", 'X', "[ <filename> | <directory> ]", "Exclude the named file or directory" + " from the archive"); static CommandOption[] opts = { create, file, xclude }; public CommandOption[] getOptions() { return opts; } public void optionMatched(CommandOption opt, String arg) { // nothing to do } public String getDescription() { return "feather options"; } }
Step 4: Parse the options. The main difference between
using the package in an object-oriented manner rather than
using the "classic" approach for command line parsing is the
lack of large conditional blocks to determine if the option
has been matched. Using the
Rather than making the programmer track the options and the
arguments, these are managed internally. Each
public static void main(String[] args) { CommandParser clp = new CommandParser("feather", "FILE..."); clp.addCommandListener(new feather()); clp.parse(args); if((file.getMatched() || xclude.getMatched()) && !create.getMatched()) { System.err.println("error: nothing to do"); clp.usage(); System.exit(-1); } String[] largs = clp.getUnhandledArguments(); if(create.getMatched() && largs.length == 0) { System.err.println("error: refusing to create empty archive."); clp.usage(); System.exit(-2); } for(int i = 0; i < largs.length; ++i) { System.out.println("largs[" + i + "] = '" + largs[i] + "'"); } if(xclude.getMatched()) { System.out.println("Excluded:"); List xas = xclude.getArgs(); for(Iterator j = xas.iterator(); j.hasNext();) { System.out.println(j.next()); } } }
Step 5: Run the program. By default, the
To print the long help message for the application, the
$ java feather --help Usage: feather [OPTION...] FILE... feather options: -c, --create Create a new archive. -f, --file=<filename> Specify the name of the archive (default is stdout). -X, --exclude=[ <filename> | <directory> ] Exclude the named file or directory from the archive Help options: -?, --help show this help message --usage show brief usage message
In a similar manner, specifying the $ java feather --usage Usage: feather [-c|--create] [-f|--file=<filename>] [-X|--exclude=[ <filename> | <directory> ]] [-?|--help] [--usage] FILE... Finally, give the program something useful to do and prove that it really recognizes all of the command-line options. $ java feather -X /tmp -X /var -c -f out.feather / largs[0] = '/' Excluded: /tmp /var That's all there is to it. The core classes allow the developer to focus on what the utility is supposed to accomplish, not spend a lot of time writing mindless, boilerplate code. This library owes a great deal to Red Hat's popt parsing library. I used popt quite a bit in the past for C and C++ command line parsing, but, while I thought it was easier than some, there were still some things which I thought were harder than they should be. Of course, popt was written for C and not C++ or Java and so can't be faulted for taking a procedural approach. None of the existing libraries for solving the problem in Java quite seemed "natural", for want of a better word, so this package is the result of me trying to build a better mousetrap. Hopefully, this example points out some of the advantages of this package over some of the other ways of solving the problem.
The complete source code for the above example is included in the
|