Reputation: 35250
What is a good way of parsing command line arguments in Java?
Upvotes: 696
Views: 497335
Reputation: 5256
Take a look at Spring Shell
Spring Shell’s features include
- A simple, annotation driven, programming model to contribute custom commands
- Use of Spring Boot auto-configuration functionality as the basis for a command plugin strategy
- Tab completion, colorization, and script execution
- Customization of command prompt, shell history file name, handling of results and errors
- Dynamic enablement of commands based on domain specific criteria
- Integration with the bean validation API
- Already built-in commands, such as clear screen, gorgeous help, exit
- ASCII art Tables, with formatting, alignment, fancy borders, etc.
Upvotes: 0
Reputation: 36844
It is 2022, time to do better than Commons CLI... :-)
Should you build your own Java command line parser, or use a library?
Many small utility-like applications probably roll their own command line parsing to avoid the additional external dependency. picocli may be an interesting alternative.
Picocli is a modern library and framework for building powerful, user-friendly, GraalVM-enabled command line apps with ease. It lives in 1 source file so apps can include it as source to avoid adding a dependency.
It supports colors, autocompletion, subcommands, and more. Written in Java, usable from Groovy, Kotlin, Scala, etc.
Features:
<command> -xvfInputFile
as well as <command> -x -v -f InputFile
)"1..*"
, "3..5"
The usage help message is easy to customize with annotations (without programming). For example:
(source)
I couldn't resist adding one more screenshot to show what usage help messages are possible. Usage help is the face of your application, so be creative and have fun!
Disclaimer: I created picocli. Feedback or questions very welcome.
Upvotes: 125
Reputation: 7328
I have been trying to maintain a list of Java CLI parsers.
Upvotes: 264
Reputation: 340486
Check these out:
Or roll your own:
For instance, this is how you use commons-cli
to parse 2 string arguments:
import org.apache.commons.cli.*;
public class Main {
public static void main(String[] args) throws Exception {
Options options = new Options();
Option input = new Option("i", "input", true, "input file path");
input.setRequired(true);
options.addOption(input);
Option output = new Option("o", "output", true, "output file");
output.setRequired(true);
options.addOption(output);
CommandLineParser parser = new DefaultParser();
HelpFormatter formatter = new HelpFormatter();
CommandLine cmd = null;//not a good practice, it serves it purpose
try {
cmd = parser.parse(options, args);
} catch (ParseException e) {
System.out.println(e.getMessage());
formatter.printHelp("utility-name", options);
System.exit(1);
}
String inputFilePath = cmd.getOptionValue("input");
String outputFilePath = cmd.getOptionValue("output");
System.out.println(inputFilePath);
System.out.println(outputFilePath);
}
}
usage from command line:
$> java -jar target/my-utility.jar -i asd
Missing required option: o
usage: utility-name
-i,--input <arg> input file path
-o,--output <arg> output file
Upvotes: 515
Reputation: 82
I want to show you my implementation: ReadyCLI
Advantages:
I developed this project as I needed new features (options, flag, sub-commands) and that could be used in the simplest possible way in my projects.
Upvotes: 4
Reputation: 10559
If you are already using Spring Boot, argument parsing comes out of the box.
If you want to run something after startup, implement the ApplicationRunner
interface:
@SpringBootApplication
public class Application implements ApplicationRunner {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(ApplicationArguments args) {
args.containsOption("my-flag-option"); // test if --my-flag-option was set
args.getOptionValues("my-option"); // returns values of --my-option=value1 --my-option=value2
args.getOptionNames(); // returns a list of all available options
// do something with your args
}
}
Your run
method will be invoked after the context has started up successfully.
If you need access to the arguments before you fire up your application context, you can just simply parse the application arguments manually:
@SpringBootApplication
public class Application implements ApplicationRunner {
public static void main(String[] args) {
ApplicationArguments arguments = new DefaultApplicationArguments(args);
// do whatever you like with your arguments
// see above ...
SpringApplication.run(Application.class, args);
}
}
And finally, if you need access to your arguments in a bean, just inject the ApplicationArguments
:
@Component
public class MyBean {
@Autowired
private ApplicationArguments arguments;
// ...
}
Upvotes: 10
Reputation: 2710
Maybe these
JArgs command line option parsing suite for Java - this tiny project provides a convenient, compact, pre-packaged and comprehensively documented suite of command line option parsers for the use of Java programmers. Initially, parsing compatible with GNU-style 'getopt' is provided.
ritopt, The Ultimate Options Parser for Java - Although, several command line option standards have been preposed, ritopt follows the conventions prescribed in the opt package.
Upvotes: 7
Reputation: 2050
For Spring users, we should mention also https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/SimpleCommandLinePropertySource.html and his twin brother https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/JOptCommandLinePropertySource.html (JOpt implementation of the same functionality). The advantage in Spring is that you can directly bind the command line arguments to attributes, there is an example here https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/CommandLinePropertySource.html
Upvotes: 0
Reputation: 21
As one of the comments mentioned earlier (https://github.com/pcj/google-options) would be a good choice to start with.
One thing I want to add-on is:
1) If you run into some parser reflection error, please try use a newer version of the guava. in my case:
maven_jar(
name = "com_google_guava_guava",
artifact = "com.google.guava:guava:19.0",
server = "maven2_server",
)
maven_jar(
name = "com_github_pcj_google_options",
artifact = "com.github.pcj:google-options:jar:1.0.0",
server = "maven2_server",
)
maven_server(
name = "maven2_server",
url = "http://central.maven.org/maven2/",
)
2) When running the commandline:
bazel run path/to/your:project -- --var1 something --var2 something -v something
3) When you need the usage help, just type:
bazel run path/to/your:project -- --help
Upvotes: 0
Reputation: 362
I know most people here are going to find 10 million reasons why they dislike my way, but nevermind. I like to keep things simple, so I just separate the key from the value using a '=' and store them in a HashMap like this:
Map<String, String> argsMap = new HashMap<>();
for (String arg: args) {
String[] parts = arg.split("=");
argsMap.put(parts[0], parts[1]);
}
You could always maintain a list with the arguments you are expecting, to help the user in case he forgot an argument or used a wrong one... However, if you want too many features this solution is not for you anyway.
Upvotes: 17
Reputation: 3882
Argparse4j is best I have found. It mimics Python's argparse libary which is very convenient and powerful.
Upvotes: 3
Reputation: 605
This is Google's command line parsing library open-sourced as part of the Bazel project. Personally I think it's the best one out there, and far easier than Apache CLI.
https://github.com/pcj/google-options
maven_jar(
name = "com_github_pcj_google_options",
artifact = "com.github.pcj:google-options:jar:1.0.0",
sha1 = "85d54fe6771e5ff0d54827b0a3315c3e12fdd0c7",
)
dependencies {
compile 'com.github.pcj:google-options:1.0.0'
}
<dependency>
<groupId>com.github.pcj</groupId>
<artifactId>google-options</artifactId>
<version>1.0.0</version>
</dependency>
Create a class that extends OptionsBase
and defines your @Option
(s).
package example;
import com.google.devtools.common.options.Option;
import com.google.devtools.common.options.OptionsBase;
import java.util.List;
/**
* Command-line options definition for example server.
*/
public class ServerOptions extends OptionsBase {
@Option(
name = "help",
abbrev = 'h',
help = "Prints usage info.",
defaultValue = "true"
)
public boolean help;
@Option(
name = "host",
abbrev = 'o',
help = "The server host.",
category = "startup",
defaultValue = ""
)
public String host;
@Option(
name = "port",
abbrev = 'p',
help = "The server port.",
category = "startup",
defaultValue = "8080"
)
public int port;
@Option(
name = "dir",
abbrev = 'd',
help = "Name of directory to serve static files.",
category = "startup",
allowMultiple = true,
defaultValue = ""
)
public List<String> dirs;
}
Parse the arguments and use them.
package example;
import com.google.devtools.common.options.OptionsParser;
import java.util.Collections;
public class Server {
public static void main(String[] args) {
OptionsParser parser = OptionsParser.newOptionsParser(ServerOptions.class);
parser.parseAndExitUponError(args);
ServerOptions options = parser.getOptions(ServerOptions.class);
if (options.host.isEmpty() || options.port < 0 || options.dirs.isEmpty()) {
printUsage(parser);
return;
}
System.out.format("Starting server at %s:%d...\n", options.host, options.port);
for (String dirname : options.dirs) {
System.out.format("\\--> Serving static files at <%s>\n", dirname);
}
}
private static void printUsage(OptionsParser parser) {
System.out.println("Usage: java -jar server.jar OPTIONS");
System.out.println(parser.describeOptions(Collections.<String, String>emptyMap(),
OptionsParser.HelpVerbosity.LONG));
}
}
https://github.com/pcj/google-options
Upvotes: 12
Reputation: 5137
airline @ Github looks good. It is based on annotation and is trying to emulate Git command line structures.
Upvotes: 4
Reputation: 10013
If you are familiar with gnu getopt, there is a Java port at: http://www.urbanophile.com/arenn/hacking/download.htm.
There appears to be a some classes that do this:
Upvotes: 5
Reputation: 21
If you want something lightweight (jar size ~ 20 kb) and simple to use, you can try argument-parser. It can be used in most of the use cases, supports specifying arrays in the argument and has no dependency on any other library. It works for Java 1.5 or above. Below excerpt shows an example on how to use it:
public static void main(String[] args) {
String usage = "--day|-d day --mon|-m month [--year|-y year][--dir|-ds directoriesToSearch]";
ArgumentParser argParser = new ArgumentParser(usage, InputData.class);
InputData inputData = (InputData) argParser.parse(args);
showData(inputData);
new StatsGenerator().generateStats(inputData);
}
More examples can be found here
Upvotes: 2
Reputation: 15608
Take a look at the more recent JCommander.
I created it. I’m happy to receive questions or feature requests.
Upvotes: 327
Reputation: 13347
Someone pointed me to args4j lately which is annotation based. I really like it!
Upvotes: 24
Reputation: 404
I wrote another one: http://argparse4j.sourceforge.net/
Argparse4j is a command line argument parser library for Java, based on Python's argparse.
Upvotes: 6
Reputation: 199333
Yeap.
I think you're looking for something like this: http://commons.apache.org/cli
The Apache Commons CLI library provides an API for processing command line interfaces.
Upvotes: 8
Reputation: 24370
I've used JOpt and found it quite handy: http://jopt-simple.sourceforge.net/
The front page also provides a list of about 8 alternative libraries, check them out and pick the one that most suits your needs.
Upvotes: 23
Reputation: 45408
Take a look at the Commons CLI project, lots of good stuff in there.
Upvotes: 9