【问题标题】:How do I parse command line arguments in Java?如何在 Java 中解析命令行参数?
【发布时间】:2010-09-26 22:21:48
【问题描述】:

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

【问题讨论】:

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

标签: java command-line command-line-arguments


【解决方案1】:

看看这些:

或者自己动手:


例如,这是您使用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 岁)。也就是说,应该平衡良好的编辑以避免被视为垃圾邮件并且必须披露从属关系。感谢您指出这一点。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    也许这些

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        是的。

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

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

        【讨论】:

          【解决方案6】:
          【解决方案7】:

          最近有人将我指向args4j,它是基于注释的。我真的很喜欢!

          【讨论】:

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

          看看最近的JCommander。

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

          【讨论】:

          • 很高兴你喜欢 JCommander :-) 我不想为处理标志的方式添加太多语义,所以你只需要在你使用的注释中添加同义词:@Parameter(names = { "-h", "--help" }) 我认为这是一个合理的折衷方案。
          • 很棒的工具。强大、灵活,您不必处理烦人的传统选项解析器。
          • 是的,我想我会按照您编写 JCommander 的方式编写自己的命令行参数解析器。伟大的工作。
          • @CedricBeust,这是一个很棒的图书馆,非常感谢。由于我们可以定义自己的 Args 类,然后可以在不依赖库类的情况下传递这些类,因此非常灵活。
          • 让竞争从水中脱颖而出!
          【解决方案9】:

          【讨论】:

          • @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 之类的作者致歉 - 我不得不做出一个有点武断的排名,并选择了前五名,显然列表中的其他项目很受欢迎并且仍在积极开发中。
          • 我挑战某人包括每个解析器的最后一个稳定版本的日期。
          【解决方案10】:

          我又写了一篇:http://argparse4j.sourceforge.net/

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

          【讨论】:

          • 欢迎来到 Stack Overflow!感谢您发布您的答案!请务必仔细阅读FAQ on Self-Promotion。
          【解决方案11】:

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

          【讨论】:

            【解决方案12】:

            这是作为 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'
            }
            

            Maven

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

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

            【讨论】:

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

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

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

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

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

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

            特点:

            • 基于注释:声明性、避免重复和表达程序员意图
            • 方便:解析用户输入并使用一行代码运行您的业务逻辑
            • 强输入一切 - 命令行选项以及位置参数
            • POSIX 集群空头期权(&lt;command&gt; -xvfInputFile 和 &lt;command&gt; -x -v -f InputFile)
            • 细粒度控制:允许最小、最大和可变参数数量的 arity 模型,例如,"1..*"、"3..5"
            • 子命令(可以嵌套到任意深度)
            • 功能丰富:可组合的 arg 组、拆分引用的 arg、可重复的子命令等等
            • 用户友好:使用帮助消息使用颜色将选项名称等重要元素与其他使用帮助进行对比,以减少认知负担用户
            • 以 GraalVM native image 的身份分发您的应用
            • 适用于 Java 5 及更高版本
            • 广泛细致documentation

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

            (source)

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

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

            【讨论】:

            • 纯粹的天才!很遗憾,这个答案被埋在了底部。 Apache Commons CLI 冗长、错误,并且很长时间没有更新。而且我不想使用 Google 的 CLI 解析器,因为我不想要基于我的命令行参数使用历史的有针对性的广告。但无论如何,它看起来比 picocli 更冗长。
            • 我第二个@Pete 在这里...我浏览了上面的列表,这完全是浪费时间,因为它被埋在了底部。这应该是一英里的最佳答案。做得好! apache CLI 或大多数其他解析器无法满足我的要求。即使对于 picocli,它们也具有挑战性,但它能够为我提供最接近我想要的语法/行为的东西,并且足够灵活,可以破解我真正需要的东西。作为奖励,由于 ANSI 的东西,它看起来很棒。
            • @ShaiAlmog 票数最高的答案是 10 岁且已过时。我同意在 2019 年推荐 Commons CLI 会误导恕我直言。请考虑rewriting 最佳答案,以使其更新。
            • 我看到您已经尝试过了,我认为这对我也不起作用...如果您选择像 1Picoli 这样的名称,我们可以按字母顺序对第三个答案进行排序;-)
            • @RemkoPopma 我在接受的答案中添加了pico。希望它能坚持下去。
            【解决方案14】:

            如果你想要一些轻量级(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

            【讨论】:

            • 链接已失效。你杀了你的项目吗? :-(
            【解决方案15】:

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

            【讨论】:

              【解决方案16】:

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

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

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

              【讨论】:

                【解决方案17】:

                作为前面提到的 cmets 之一 (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
                

                【讨论】:

                  【解决方案18】:
                  【解决方案19】:

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

                  【讨论】:

                  • 这太棒了:)。
                  【解决方案20】:

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

                  优点:

                  • 适合懒惰的程序员:需要学习的课程数量非常少,只需查看存储库中 README 中的两个小示例,您就已经完成了 90% 的学习;在没有任何其他知识的情况下开始编写 CLI/解析器; ReadyCLI 允许以最自然的方式编写 CLI;
                  • 它的设计考虑了开发者体验;它主要使用 Lambda 表达式的 Builder 设计模式和功能接口,以实现非常快速的编码;
                  • 支持Options、Flags和Sub-Commands;
                  • 它允许从命令行解析参数并构建更复杂和交互式的 CLI;
                  • 可以像在任何其他 I/O 接口(例如套接字)上一样轻松地在标准 I/O 上启动 CLI;
                  • 它为命令文档提供了强大的支持。

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

                  【讨论】:

                    猜你喜欢
                    • 2012-04-29
                    • 2011-04-27
                    • 2010-09-16
                    • 2014-12-18
                    相关资源
                    最近更新 更多