我知道这个问题已经被提出,但我正在寻找具有特定功能的Java cli解析器。 我希望它能够定义命令行树,从而使用子命令(和多个级别深度)。 因此,在我到达选项之前,我可以有3-4级命令。 这些子命令是互斥的。 感谢
答案 0 :(得分:13)
可以使用JCommander完成。从本质上讲,每个JCommander
对象都是一个具有任意数量参数和/或任意数量的嵌套子命令的命令,其中顶部JCommander
对象是 root 命令。命令参数始终特定于它们已声明的命令,并且不会干扰其他命令的参数。添加子命令的界面不是很直观,但可以实现(参见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,使用组合模式(参见doc here):
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
等等。
答案 1 :(得分:2)
picocli支持任意深度的嵌套子命令。
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样式和颜色的使用帮助。
请注意,除了选项和位置参数外,用法帮助还列出了已注册的子命令。
可以使用注释轻松自定义使用帮助。
答案 2 :(得分:0)
答案 3 :(得分:0)
我认为将这个多级命令拆分成几个CLI工具会更好。
而不是:
program cmd sub-cmd sub-sub-cmd -option1 argument -option2 argument
在程序名称后附加一个或两个级别:
program-cmd-sub-cmd sub-sub-cmd -option1 argument -option2 argument
真实的例子:
svn-add -q -N foo.c
您可以将所有必需的类保留在单个JAR中(并根据需要重复使用它们),只需添加几个“主要”入口点。对于基本的CLI解析,我还建议JCommander
。