最近在看pulsar源码时,发现他们使用了JCommander来开发命令行交互程序,便对这个framework产生了兴趣。 传统意义上讲,JAVA并不是开发命令行程序最合适的语言,但是因为依赖一些特定JAVA库(特别是大数据相关的)的CLI程序,用java来开发却是最方便的。
首先我们先了解下常见的linux命令行风格:
Unix是从贝尔实验室开发的AT&T Unix系统上原有的命令继承下来的。
ls -a
ls -lah
-后面可以跟多个字母,多个字母就是多个参数
ps aux
参数不带-
两个减号 – 加参数,一般后边的参数是跟上一个单词或短语
ps --no-headers
当然Unix和GUN风格很多混用,如ls -a 等于ls --all,-h 往往对应 --help
比如java的命令行,-后面直接是单词
java -version
java -Djava.awt.headless=true -Djava.net.useSystemProxies=true Foo
首先我们看下官方的demo快速入门
java源程序
public class JCommanderTest {
@Parameter
public List<String> parameters = Lists.newArrayList();
@Parameter(names = { "-log", "-verbose" }, description = "Level of verbosity")
public Integer verbose = 1;
@Parameter(names = "-groups", description = "Comma-separated list of group names to be run")
public String groups;
@Parameter(names = "-debug", description = "Debug mode")
public boolean debug = false;
@DynamicParameter(names = "-D", description = "Dynamic parameters go here")
public Map<String, String> dynamicParams = new HashMap<String, String>();
}
所以我们这样调用
JCommanderTest jct = new JCommanderTest();
String[] argv = { "-log", "2", "-groups", "unit1,unit2,unit3",
"-debug", "-Doption=value", "a", "b", "c" };
JCommander.newBuilder()
.addObject(jct)
.build()
.parse(argv);
Assert.assertEquals(2, jct.verbose.intValue());
Assert.assertEquals("unit1,unit2,unit3", jct.groups);
Assert.assertEquals(true, jct.debug);
Assert.assertEquals("value", jct.dynamicParams.get("option"));
Assert.assertEquals(Arrays.asList("a", "b", "c"), jct.parameters);
不难发现,JCommander有如下几个特点:
其中help最为强大,如demo
@Parameter(names = "--help", help = true, order = 5)
private boolean help;
则如下使用即可生成完善的文档
if (help) {
jCommander.usage();
return;
}
Usage: <main class> [options]
Options:
--help
-debug
Debug mode
Default: true
-host
The host
Default: []
-password
Connection password
在实际程序中,我们往往会遇到很多类似要输入密码的场景。此时我们并不希望密码出现在history中,你可以使用password这种类型,这样JCommander会让你在console中输入。
public class ArgsPassword {
@Parameter(names = "-password", description = "Connection password", password = true)
private String password;
}
当用户产生于预期不一致的输入时,我们希望便捷地使用正则表达式来校验这些值。
@Parameter(names = "-v", validateWith = RegexValidator.class)
@Regex("(2\\.0|1\\.0)")
private String version = "2.0";
当然我们还可以使用Apache Commons CLI实现相关功能
文章首发云+ 社区:https://cloud.tencent.com/developer/article/1366912