首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Java CLI解析器

Java CLI解析器
EN

Stack Overflow用户
提问于 2012-04-15 14:41:15
回答 4查看 4K关注 0票数 10

我知道这个问题已经被问过了,但我正在寻找具有特定功能的Java cli解析器。我希望它能够定义命令行树,从而使用子命令(以及多个级别的深度)。因此,在我到达选项之前,我可以有3-4级的命令。这些子命令是互斥的。谢谢

EN

回答 4

Stack Overflow用户

发布于 2012-04-15 20:22:55

可以使用JCommander来完成。每个JCommander对象本质上是具有任意数量的参数和/或任意数量的嵌套子命令的命令,其中顶层JCommander对象是根命令。命令参数始终特定于为其声明命令的命令,并且不会干扰其他命令的参数。添加子命令的界面不是很直观,但也是可能的(参见addCommand方法())

这是一个概念验证测试类:

代码语言:javascript
运行
复制
public class Test{

@Test
public void nestedSubCommandTest() {
    GeneralOptions generalOpts = new GeneralOptions();
    JCommander jc = new JCommander(generalOpts);

    Command command = new Command();
    JCommander jc_command = addCommand(jc, "command", command);

    SubCommand1 subcommand1 = new SubCommand1();
    JCommander jc_subcommand1 = addCommand(jc_command, "subcommand1",
            subcommand1);

    SubCommand2 subcommand2 = new SubCommand2();
    JCommander jc_subcommand2 = addCommand(jc_subcommand1, "subcommand2",
            subcommand2);

    SubCommand3 subcommand3 = new SubCommand3();
    addCommand(jc_subcommand2, "subcommand3", subcommand3);

    jc.parse("--general-opt", 
        "command", "--opt", 
        "subcommand1",
        "subcommand2", "--sub-opt2", 
        "subcommand3", "--sub-opt3");

    assertTrue(generalOpts.opt);// --general-opt was set
    assertTrue(command.opt);// command --opt was set
    assertFalse(subcommand1.opt);// subcommand1 --sub-opt1 was not set
    assertTrue(subcommand2.opt);// subcommand2 --sub-opt2 was set
    assertTrue(subcommand3.opt);// subcommand3 --sub-opt3 was set
}

private static JCommander addCommand(JCommander parentCommand,
        String commandName, Object commandObject) {
    parentCommand.addCommand(commandName, commandObject);
    return parentCommand.getCommands().get(commandName);
}

public static class GeneralOptions {
    @Parameter(names = "--general-opt")
    public boolean opt;
}

@Parameters
public static class Command {
    @Parameter(names = "--opt")
    public boolean opt;
}

@Parameters
public static class SubCommand1 {
    @Parameter(names = "--sub-opt1")
    public boolean opt;
}

@Parameters
public static class SubCommand2 {
    @Parameter(names = "--sub-opt2")
    public boolean opt;
}

@Parameters
public static class SubCommand3 {
    @Parameter(names = "--sub-opt3")
    public boolean opt;
}
}

编辑:如何重用命令。

解决方案1,使用继承:

代码语言:javascript
运行
复制
  public class CommonArgs{
    @Parameter(names="--common-opt")
    public boolean isCommonOpt;
  }

  @Parameters(description = "my command 1")
  public class MyCommand1 extends CommonArgs{}

  @Parameters(description = "my command 2")
  public class MyCommand2 extends CommonArgs{}

我认为这个的用法和行为是显而易见的。一个缺点是您只能从一个类进行扩展,这可能会限制将来的可重用性。

解决方案2,使用组合模式(参见doc here):

代码语言:javascript
运行
复制
  public class CommonArgs{
    @Parameter(names="--common-opt")
    public boolean isCommonOpt;
  }

  @Parameters(description = "my command 1")
  public class MyCommand1{
    @ParametersDelegate
    public CommonArgs commonArgs = new CommonArgs();
  }

  @Parameters(description = "my command 2")
  public class MyCommand2{
    @ParametersDelegate
    public CommonArgs commonArgs = new CommonArgs();
  }

在这里,嵌套的commonArgs类的参数将被视为命令类的直接参数。您可以根据需要添加任意数量的代理,甚至可以在其他代理中嵌套代理等等。要在解析后获得委托选项的值,只需执行myCommand1.commonArgs.isCommonOpt等操作。

票数 14
EN

Stack Overflow用户

发布于 2017-06-30 13:06:55

picocli支持任意深度的嵌套子命令。

代码语言:javascript
运行
复制
CommandLine commandLine = new CommandLine(new MainCommand())
        .addSubcommand("cmd1", new ChildCommand1()) // 1st level
        .addSubcommand("cmd2", new ChildCommand2())
        .addSubcommand("cmd3", new CommandLine(new ChildCommand3()) // 2nd level
                .addSubcommand("cmd3sub1", new GrandChild3Command1())
                .addSubcommand("cmd3sub2", new GrandChild3Command2())
                .addSubcommand("cmd3sub3", new CommandLine(new GrandChild3Command3()) // 3rd
                        .addSubcommand("cmd3sub3sub1", new GreatGrandChild3Command3_1())
                        .addSubcommand("cmd3sub3sub2", new GreatGrandChild3Command3_2())
                                // etc
                )
        );

您可能也喜欢它的用法帮助ANSI样式和颜色。

请注意,使用帮助除了列出选项和位置参数外,还列出了已注册的子命令。

使用帮助可以通过注释轻松地进行自定义。

  • annotation-based
  • git-style subcommands
  • nested sub-subcommands
  • strongly类型的选项parameters
  • strongly类型的位置parameters
  • customizable类型conversion
  • multi-value options
  • intuitive consumes
  • fluent API
  • POSIX-style字段的参数数量options
  • allows聚集的短选项

GNU样式长

  • 任何选项前缀
  • ANSI颜色用法用法帮助
  • 单个源文件: include as source可使应用程序保持单个jar
票数 3
EN

Stack Overflow用户

发布于 2012-04-15 18:35:32

如果你的命令表达式很复杂,那么你可以考虑定义语法,编写它的BNF,并使用JavaCCAntLR等库来创建自己的解析器。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10160086

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档