Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/392.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java CLI解析器_Java_Command Line Interface_Subcommand - Fatal编程技术网

Java CLI解析器

Java CLI解析器,java,command-line-interface,subcommand,Java,Command Line Interface,Subcommand,我知道已经有人问过这个问题,但我正在寻找具有特定功能的JavaCLI解析器。 我希望它能够定义命令行树,从而使用子命令(以及多个级别的深度)。 因此,在进入选项之前,我可以使用3-4级命令。 这些子命令是相互排斥的。 谢谢如果您的命令表达式很复杂,那么您可以考虑定义语法,编写其BNF,并使用类似或的库来创建您自己的解析器。可以使用。每个JCommander对象本质上都是一个具有任意数量参数和/或任意数量嵌套子命令的命令,其中顶部的JCommander对象是根命令。命令参数始终特定于为其声明的命令

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

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

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

下面是一个概念验证测试类:

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,使用继承:

  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,使用组合模式(请参阅):


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

我认为最好将此多级命令拆分为几个CLI工具

而不是:
program cmd sub cmd sub cmd-option1参数-option2参数

将一个或两个级别附加到程序名:
program cmd sub cmd sub cmd-option1参数-option2参数

实词示例:
svn add-q-N foo.c

您可以将所有必需的类保存在单个JAR中(并尽可能重用它们),只需添加几个“主”入口点。对于基本CLI解析,我还建议
JCommander

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

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样式和颜色的使用帮助

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

使用说明可以通过注释轻松定制

  • 基于注释的
  • git风格的子命令
  • 嵌套子命令
  • 强类型选项参数
  • 强类型位置参数
  • 可自定义类型转换
  • 多值选项
  • 一个字段使用多少参数的直观模型
  • fluent API
  • POSIX样式群集短选项
  • GNU风格的长选项
  • 允许任何选项前缀
  • ANSI颜色使用帮助
  • 自定义使用帮助
  • 单源文件:包含为源文件,以使应用程序保持一个jar

您可以发布几个您想要解析的命令示例吗?命令子命令子命令-选项1参数-选项2参数HI。事实上,我整天都在和JCommander玩。我对此没有什么问题。解析器的异常根本不清楚,我无法向用户介绍它们。另一件事是,我需要为每个命令创建一个命令类(我有很多),我不能重用它们,因为注释不是泛型。哦,usage()并没有真正打印出所有的子命令和选项。JCommander可能不是以子命令作为最高优先级设计的,如果你愿意的话,它更像是一个隐藏的特性。没有那么多的例外情况,所以你可以用一些更有用的东西来包装它们。至于
usage()
似乎没有对sub命令的官方支持,因此您必须进行一些黑客攻击,或者只是手工编写。我不能同意重用,但是,可重用性是我喜欢JCommander的一个方面。如果你给我一个具体的例子,我也许能帮上忙。非常感谢。例如,我有两个命令,它们有不同的命名和描述,但它们都有相同的参数。所以为了设置描述,我必须有不同的command类实例,尽管类中的parareter是相同的。希望这能对这个问题有所帮助。啊,我一直在寻找如何设置命令描述。原来我只需要添加`@Parameters(description=“my command 2”)`非常感谢!
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
                )
        );