在 Java 中解析命令行参数的好方法是什么?
20 回答
检查这些:
或者自己动手:
例如,这是您commons-cli
用来解析 2 个字符串参数的方式:
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);
}
}
从命令行使用:
$> 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
看看更新的JCommander。
我创造了它。我很高兴收到问题或功能请求。
我一直在尝试维护Java CLI 解析器列表。
- 航空公司
- argparse4j
- 参数解析器
- args4j
- 克莱尔
- cli解析器
- CmdLn
- 命令行
- DocOpt.java
- 海豚 getopt
- DPML CLI(Jakarta Commons CLI2 分支)
- Matthias Laux 博士
- 雅加达公共 CLI
- 空话
- jargp
- 罐子
- java-getopt
- 博克
- JCLAP
- 命令行
- jcommander
- 突击队
- Jewelcli(我写的)
- 选择简单
- jsap
- 自然cli
- Object Mentor CLI 文章(有关重构和 TDD 的更多信息)
- 解析-cmd
- ritopt
- 罗普
- TE-代码命令
- picocli具有 ANSI 彩色使用帮助和自动完成功能
现在是 2022 年,是时候比 Commons CLI 做得更好...... :-)
您应该构建自己的 Java 命令行解析器,还是使用库?
许多类似实用程序的小型应用程序可能会使用自己的命令行解析来避免额外的外部依赖。picocli可能是一个有趣的选择。
Picocli 是一个现代库和框架,用于轻松构建功能强大、用户友好、支持 GraalVM 的命令行应用程序。它存在于 1 个源文件中,因此应用程序可以将其作为源包含以避免添加依赖项。
它支持颜色、自动完成、子命令等。用 Java 编写,可用于 Groovy、Kotlin、Scala 等。
特征:
- 基于注释:声明性,避免重复并表达程序员意图
- 方便:解析用户输入并用一行代码运行您的业务逻辑
- 强类型的一切 - 命令行选项以及位置参数
- POSIX 集群空头期权(
<command> -xvfInputFile
以及<command> -x -v -f InputFile
) - 细粒度控制:一个允许最小、最大和可变参数数量的模型,例如
"1..*"
,"3..5"
- 子命令(可以嵌套到任意深度)
- 功能丰富:可组合的 arg 组、拆分引用的 args、可重复的子命令等等
- 用户友好:使用帮助消息使用颜色将选项名称等重要元素与其他使用帮助进行对比,以减少用户的认知负担
- 将您的应用程序分发为GraalVM 原生映像
- 适用于Java 5及更高版本
- 广泛而细致的文档
使用帮助消息很容易通过注释自定义(无需编程)。例如:
(来源)
我忍不住再添加一张屏幕截图来显示可能的使用帮助消息。使用帮助是您的应用程序的面孔,所以要有创意,玩得开心!
免责声明:我创建了 picocli。非常欢迎反馈或问题。
最近有人向我指出了基于注释的args4j。我很喜欢!
我使用过 JOpt,发现它非常方便:http: //jopt-simple.sourceforge.net/
首页还提供了大约 8 个替代库的列表,请查看它们并选择最适合您需求的库。
这是作为 Bazel 项目的一部分开源的 Google 命令行解析库。就我个人而言,我认为它是最好的,而且比 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>
用法
创建一个扩展OptionsBase
并定义您的@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;
}
解析参数并使用它们。
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));
}
}
我知道这里的大多数人会找到 1000 万个他们不喜欢我的方式的理由,但没关系。我喜欢保持简单,所以我只需使用“=”将键与值分开,并将它们存储在 HashMap 中,如下所示:
Map<String, String> argsMap = new HashMap<>();
for (String arg: args) {
String[] parts = arg.split("=");
argsMap.put(parts[0], parts[1]);
}
您始终可以维护一个包含您期望的参数的列表,以帮助用户以防他忘记了参数或使用了错误的参数......但是,如果您想要太多功能,这个解决方案无论如何都不适合您。
看看Commons CLI项目,里面有很多好东西。
也许这些
用于 Java 的 JArgs 命令行选项解析套件——这个小型项目为 Java 程序员提供了一个方便、紧凑、预打包和全面记录的命令行选项解析器套件。最初,提供了与 GNU 风格的“getopt”兼容的解析。
ritopt,Java 的终极选项解析器- 尽管已经预先提出了几个命令行选项标准,但 ritopt 遵循 opt 包中规定的约定。
如果您已经在使用 Spring Boot,那么参数解析是开箱即用的。
如果你想在启动后运行一些东西,实现ApplicationRunner
接口:
@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
}
}
您的run
方法将在上下文成功启动后被调用。
如果您需要在启动应用程序上下文之前访问参数,您可以简单地手动解析应用程序参数:
@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);
}
}
最后,如果您需要访问 bean 中的参数,只需注入ApplicationArguments
:
@Component
public class MyBean {
@Autowired
private ApplicationArguments arguments;
// ...
}
我写了另一个:http ://argparse4j.sourceforge.net/
Argparse4j 是基于 Python 的 argparse 的 Java 命令行参数解析器库。
如果您熟悉 gnu getopt,则在以下位置有一个 Java 端口:http ://www.urbanophile.com/arenn/hacking/download.htm 。
似乎有一些类可以做到这一点:
航空公司@Github看起来不错。它基于注释,并试图模拟 Git 命令行结构。
Argparse4j 是我发现的最好的。它模仿 Python 的 argparse 库,非常方便和强大。
如果您想要一些轻量级(jar 大小 ~ 20 kb)且易于使用的东西,您可以尝试argument-parser。它可以在大多数用例中使用,支持在参数中指定数组,并且不依赖于任何其他库。它适用于 Java 1.5 或更高版本。以下摘录显示了如何使用它的示例:
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);
}
更多示例可以在这里找到
我想向你展示我的实现:ReadyCLI
好处:
- 对于懒惰的程序员:要学习的课程数量非常少,只需查看存储库中 README 上的两个小示例,您就已经完成了 90% 的学习;在没有任何其他知识的情况下开始编写 CLI/解析器;ReadyCLI 允许以最自然的方式编写 CLI;
- 它的设计考虑了开发人员体验;它主要使用 Lambda 表达式的 Builder 设计模式和功能接口,以允许非常快速的编码;
- 它支持选项、标志和子命令;
- 它允许从命令行解析参数并构建更复杂和交互式的 CLI;
- 可以像在任何其他 I/O 接口(例如套接字)上一样轻松地在标准 I/O 上启动 CLI;
- 它为命令文档提供了极大的支持。
我开发这个项目是因为我需要新功能(选项、标志、子命令)并且可以在我的项目中以最简单的方式使用。
正如前面提到的评论之一(https://github.com/pcj/google-options)将是一个不错的选择。
我想添加的一件事是:
1) 如果遇到一些解析器反射错误,请尝试使用更新版本的番石榴。就我而言:
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)运行命令行时:
bazel run path/to/your:project -- --var1 something --var2 something -v something
3)当您需要使用帮助时,只需键入:
bazel run path/to/your:project -- --help
对于 Spring 用户,我们还应该提到https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/SimpleCommandLinePropertySource.html 和他的孪生兄弟https://docs.spring .io/spring/docs/current/javadoc-api/org/springframework/core/env/JOptCommandLinePropertySource.html(相同功能的JOpt实现)。Spring 的优点是可以直接将命令行参数绑定到属性,这里有一个例子https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/ CommandLinePropertySource.html