ChatGPT解决这个技术问题 Extra ChatGPT

如何在 Java 中解析命令行参数?

在 Java 中解析命令行参数的好方法是什么?

我不建议使用 Apache Common CLI 库,因为它是非线程安全的。它使用具有静态变量和方法的有状态类来完成内部工作(例如 OptionBuilder),并且只应在单线程强控制情况下使用。
最好记住 CLI 库不是线程安全的。但是,我假设命令行解析通常在应用程序启动期间在单个线程中完成,然后根据参数,可能会启动其他线程。
请参阅 args4j 以及如何使用它的详细示例:martin-thoma.com/how-to-parse-command-line-arguments-in-java
投票决定重新开放。 @AlikElzin:确实,他们确实需要审查他们的审核过程。我怀疑有一个徽章可以结束这么多问题,并且它会诱使想要成为版主的人过分热心。
这个问题是糟糕/单行答案和工具推荐的蜜罐。它应该保持关闭。

T
TechDog

检查这些:

http://commons.apache.org/cli/

http://www.martiansoftware.com/jsap/

或者自己动手:

http://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html

例如,这是您使用 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

请注意,与许多其他 Apache 库不同,Apache CLI 没有依赖项。
许多 apache-commons 项目的一个缺点是它们获得的提交越来越少,最终被淘汰。
这是 Apache CLI 项目的“使用场景”页面,详细说明了如何快速开始使用它:commons.apache.org/cli/usage.html
@RemkoPopma 你的 picocli 库看起来很棒,真的很感谢你这样做。但是我认为您在此处和其他帖子中所做的事情(编辑已接受的答案并在其顶部宣传您的图书馆,甚至没有透露它是不是来自帖子原作者的编辑,而是您的库)是对您的审核权力的可怕滥用。将此标记为其他模组。
@AlexanderMalakhov 我想纠正一件事:anyone 可以编辑(无需审核权限),而编辑是 encouraged 以保持帖子的相关性和最新性(当前答案是 10 年)。也就是说,应该平衡良好的编辑以避免被视为垃圾邮件并且必须披露从属关系。谢谢你指出这一点。
R
Roger Fan

看看最近的 JCommander

我创造了它。我很高兴收到问题或功能请求。


很高兴你喜欢 JCommander :-) 我不想为处理标志的方式添加太多语义,所以你只需要在你使用的注释中添加同义词:@Parameter(names = { "-h", "- -help" }) 我认为这是一个合理的妥协。
很棒的工具。强大、灵活,而且您不必处理烦人的传统选项解析器。
是的,我想我会以与您编写 JCommander 完全相同的方式编写自己的命令行参数解析器。做得好。
@CedricBeust,这是一个很棒的图书馆,非常感谢。由于我们可以定义自己的 Args 类,然后可以在不依赖库类的情况下传递这些类,因此它非常灵活。
将竞争从水中吹走!
K
KraftDurchBlumen

我一直在尝试保持 list of Java CLI parsers

航空公司主动叉:https://github.com/rvesse/airline

主动分叉:https://github.com/rvesse/airline

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 彩色使用帮助和自动完成功能


@Ben Flynn 呵呵,里面有一些非常令人惊讶和有趣的形状轮子。我想这是一种几乎无害的方式来表明有不止一种方法可以做到这一点!
我注意到 JOpt Simple 的作者维护了一个非常相似的列表!我们需要的文字是将这些列表变成一个表格,列出特征和兴趣点,以便我们这些可怜的用户做出明智的选择。
我已经构建了 Rop - github.com/ryenus/rop,它具有基于注释的解决方案,您可以通过普通的类和字段声明命令和选项,这几乎是一种构建命令行解析器的声明性方式。它可以构建像 Git (single-cmd) 或 Maven (multi-cmd) 这样的应用程序。
列出的大多数项目基本上都是废弃软件。在浏览完列表后,我想说的是,在 commons-cli、jcommander、args4j、jopt-simple 和 picocli 看来,那些被积极维护和流行的大热门。向 argparse4j 和 cli-parser 之类的作者道歉——我不得不做出一个有点武断的排名,并选择了前五名,显然列表中的其他项目很受欢迎并且仍在积极开发中。
我挑战某人包括每个解析器的最后一个稳定版本的日期。
R
Remko Popma

现在是 2022 年,是时候比 Commons CLI 做得更好...... :-)

您应该构建自己的 Java 命令行解析器,还是使用库?

许多类似实用程序的小型应用程序可能会使用自己的命令行解析来避免额外的外部依赖。 picocli 可能是一个有趣的选择。

Picocli 是一个现代库和框架,用于轻松构建功能强大、用户友好、支持 GraalVM 的命令行应用程序。它存在于 1 个源文件中,因此应用程序可以将其作为源包含以避免添加依赖项。

它支持颜色、自动完成、子命令等。用 Java 编写,可用于 Groovy、Kotlin、Scala 等。

https://i.stack.imgur.com/UqZmi.png

特征:

基于注释:声明性,避免重复并表达程序员意图

方便:解析用户输入并用一行代码运行您的业务逻辑

强类型的一切 - 命令行选项以及位置参数

POSIX 集群短选项( -xvfInputFile 以及 -x -v -f InputFile)

细粒度控制:允许最小、最大和可变参数数量的 arity 模型,例如“1..*”、“3..5”

子命令(可以嵌套到任意深度)

功能丰富:可组合的 arg 组、拆分引用的 args、可重复的子命令等等

用户友好:使用帮助消息使用颜色将选项名称等重要元素与其他使用帮助进行对比,以减少用户的认知负担

将您的应用程序分发为 GraalVM 原生映像

适用于 Java 5 及更高版本

广泛而细致的文档

使用帮助消息很容易通过注释自定义(无需编程)。例如:

https://i.stack.imgur.com/hLO1d.png

我忍不住再添加一张屏幕截图来显示可能的使用帮助消息。使用帮助是您的应用程序的面孔,所以要有创意,玩得开心!

https://i.stack.imgur.com/yLsst.png

免责声明:我创建了 picocli。非常欢迎反馈或问题。


纯粹的天才!很遗憾,这个答案被埋在了底部。 Apache Commons CLI 冗长、错误,并且很长时间没有更新。而且我不想使用 Google 的 CLI 解析器,因为我不想要基于我的命令行参数使用历史的有针对性的广告。但无论如何,它看起来比 picocli 更冗长。
我在这里第二个@Pete...我浏览了上面的列表,这完全是浪费时间,而这个被埋在了底部。这应该是一英里的最佳答案。很好! apache CLI 或大多数其他解析器无法满足我的要求。即使对于 picocli,它们也具有挑战性,但它能够为我提供最接近我想要的语法/行为的东西,并且足够灵活,可以破解我真正需要的东西。作为奖励,由于 ANSI 的东西,它看起来很棒。
@ShaiAlmog 投票最多的答案是 10 岁且已过时。我同意在 2019 年推荐 Commons CLI 会误导恕我直言。请考虑 rewriting 最佳答案以使其更新。
@RemkoPopma 我将 pico 添加到已接受的答案中。希望它坚持。
这是正确答案!这个库你不能出错
D
Duncan Jones

最近有人向我指出了基于注释的 args4j。我很喜欢!


+1 为 Args4J!非常人性化、灵活且易于理解。我认为它应该是构建 Java CLI 应用程序的标准首选库。
很好,它可以处理无序(按字段顺序排序)使用打印,而 JCommander 不能,而且它更灵活。
@DanielHári 仅供参考,此功能已添加到 JCommander 中(有时在 2017 年 2 月下旬)。
建议:您可能想在答案中添加一个示例,这比仅提供外部链接更有帮助。
G
GaryF

我使用过 JOpt,发现它非常方便:http://jopt-simple.sourceforge.net/

首页还提供了大约 8 个替代库的列表,请查看它们并选择最适合您需求的库。


I
Ioannis Koumarelas

我知道这里的大多数人会找到 1000 万个他们不喜欢我的方式的理由,但没关系。我喜欢保持简单,所以我只需使用“=”将键与值分开,并将它们存储在 HashMap 中,如下所示:

Map<String, String> argsMap = new HashMap<>();
for (String arg: args) {
    String[] parts = arg.split("=");
    argsMap.put(parts[0], parts[1]);
} 

您始终可以维护一个包含您期望的参数的列表,以帮助用户以防他忘记了参数或使用了错误的参数......但是,如果您想要太多功能,这个解决方案无论如何都不适合您。


P
Peter Mortensen

这是作为 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 的类。

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));
  }

}

https://github.com/pcj/google-options


嗨,保罗。当我阅读您的答案或您的项目文档时,我不知道它可以处理什么样的命令行。例如,您可以提供类似 myexecutable -c file.json -d 42 --outdir ./out 的内容。而且我看不到您如何定义短/长/描述选项...干杯
M
Marc Novakowski

看看 Commons CLI 项目,里面有很多好东西。


O
OscarRyz

是的。

我认为您正在寻找这样的东西:http://commons.apache.org/cli

Apache Commons CLI 库提供了一个用于处理命令行界面的 API。


S
Stefan Haberl

如果您已经在使用 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;

   // ...
}

这太棒了 :)。
R
Remko Popma

也许这些

用于 Java 的 JArgs 命令行选项解析套件——这个小型项目为 Java 程序员提供了一个方便、紧凑、预打包和全面记录的命令行选项解析器套件。最初,提供了与 GNU 风格的“getopt”兼容的解析。

ritopt,Java 的终极选项解析器 - 尽管已经预先提出了几个命令行选项标准,但 ritopt 遵循 opt 包中规定的约定。


T
Tatsuhiro Tsujikawa

我写了另一个:http://argparse4j.sourceforge.net/

Argparse4j 是基于 Python 的 argparse 的 Java 命令行参数解析器库。


欢迎来到堆栈溢出!感谢您发布您的答案!请务必仔细阅读FAQ on Self-Promotion
P
Peter Mortensen

如果您熟悉 gnu getopt,那么有一个 Java 端口位于:http://www.urbanophile.com/arenn/hacking/download.htm

似乎有一些类可以做到这一点:

http://docs.sun.com/source/816-5618-10/netscape/ldap/util/GetOpt.html

http://xml.apache.org/xalan-j/apidocs/org/apache/xalan/xsltc/cmdline/getopt/GetOpt.html


P
Peter Mortensen

airline @ Github 看起来不错。它基于注释,并试图模拟 Git 命令行结构。


P
Peter Mortensen

Argparse4j 是我发现的最好的。它模仿 Python 的 argparse 库,非常方便和强大。


S
Salvatore Giampà

我想向您展示我的实现:ReadyCLI

优点:

对于懒惰的程序员:要学习的课程非常少,只需查看存储库中 README 上的两个小示例,您就已经完成了 90% 的学习;在没有任何其他知识的情况下开始编写 CLI/解析器; ReadyCLI 允许以最自然的方式编写 CLI;

它的设计考虑了开发人员体验;它主要使用 Lambda 表达式的 Builder 设计模式和功能接口,以允许非常快速的编码;

它支持选项、标志和子命令;

它允许从命令行解析参数并构建更复杂和交互式的 CLI;

可以像在任何其他 I/O 接口(例如套接字)上一样轻松地在标准 I/O 上启动 CLI;

它为命令文档提供了极大的支持。

我开发这个项目是因为我需要新功能(选项、标志、子命令)并且可以在我的项目中以最简单的方式使用。


H
Himanshu Shekhar

如果您想要一些轻量级(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);
}

可以找到更多示例 here


链接死了。你杀了你的项目吗? :-(
s
stevens

正如前面提到的评论之一 (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