Apache Commons CLI官方文档翻译 —— 快速构建命令行启动模式,
Apache Commons CLI官方文档翻译 —— 快速构建命令行启动模式,
昨天已经联系过几个基本的命令行参数使用场景,可以参考这里
通过使用Apache Commons CLI可以帮助开发者快速构建命令行启动模式,并可以快速生成帮助指令,基于用户启动参数提供不同的服务。
入门样例
下面就举个例子,比如我想输入命令:
xxx -t
从而打印出当前的时间。
定义阶段——创建选项
首先要创建Options对象,然后添加Option对象.
// create Options object Options options = new Options(); // add t option options.addOption("t", false, "display current time");
其中addOption
方法有三个参数:
- 第一个参数是字符串类型,代表命令的参数。
- 第二个参数是Bool型,代表该选项是否需要额外的参数。
- 第三个参数是该选项的描述信息。
上面的例子就代表,t选项不需要参数,它的意思是显示当前时间
。
解析阶段——解析命令行参数
CLI通过CommandLineParser的parse方法解析命令行参数。有好几种CommandLineParser的实现类,推荐使用的是DefaultParser。看源码除了这个DefaultParser,其他的都被打上了@Deprecated标记。
除去这个DefaultParser以外,还有一个抽象类实现了CommandLineParser接口——Parser,这个Parser有三个子类:
- BasicParser
- GnuParser
- PosixParser
CommandLineParser parser = new DefaultParser(); CommandLine cmd = parser.parse( options, args);
询问阶段—— 判断命令行中出现了哪个选项
现在就可以检查是否存在这个t选项了,首先需要在CommandLine对象中进行查询。hasOption
方法可以通过选项的名字,判断命令行是否出现该命令。出现则返回true,否则返回false。
if(cmd.hasOption("t")) { // print the date and time } else { // print the date }
全部代码
public class DateApp { public static void main(String[] args) { String[] arg = {"-t"}; // String[] arg = {}; try { testOption(arg); } catch (ParseException e) { e.printStackTrace(); } } static void testOption(String[] args) throws ParseException{ Options options = new Options(); options.addOption("t", false, "display current time"); CommandLineParser parser = new DefaultParser(); CommandLine cmd = parser.parse( options, args); if(cmd.hasOption("t")) { System.out.println((new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date())); }else { System.out.println((new SimpleDateFormat("yyyy-MM-dd")).format(new Date())); } } }
进阶样例
下面这个例子继承自DateApp,并且提供了根据城市显示时间和日期的功能。为了实现这个命令,会增加一个c
选项,来添加城市信息。
// add c option options.addOption("c", true, "country code");
第二个参数这时设置为true,就代表它需要额外的参数。
获得参数值
CommandLine对象的getOptionValue方法可以获取到参数的值。
// get c option value String countryCode = cmd.getOptionValue("c"); if(countryCode == null) { // print default date }else { // print date for country specified by countryCode }
此时如果只有c选项,没有参数,就会报错
org.apache.commons.cli.MissingArgumentException: Missing argument for option: c at org.apache.commons.cli.DefaultParser.checkRequiredArgs(DefaultParser.java:211) at org.apache.commons.cli.DefaultParser.parse(DefaultParser.java:125) at org.apache.commons.cli.DefaultParser.parse(DefaultParser.java:76) at org.apache.commons.cli.DefaultParser.parse(DefaultParser.java:60) at hangout.study.InternationalDateApp.testOption(InternationalDateApp.java:29) at hangout.study.InternationalDateApp.main(InternationalDateApp.java:18)
全部代码
public class InternationalDateApp { public static void main(String[] args) { String[] arg = {"-t","-c","hello"}; // String[] arg = {"-t","-c"}; // String[] arg = {}; try { testOption(arg); } catch (ParseException e) { e.printStackTrace(); } } static void testOption(String[] args) throws ParseException{ Options options = new Options(); options.addOption("t", false, "display current time"); options.addOption("c", true, "country code"); CommandLineParser parser = new DefaultParser(); CommandLine cmd = parser.parse( options, args); if(cmd.hasOption("t")) { System.out.println((new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date())+" in "+cmd.getOptionValue("c")); }else { System.out.println((new SimpleDateFormat("yyyy-MM-dd")).format(new Date())); } } }
此时运行代码,则会正确输出信息:
2016-06-23 21:18:50 in hello
Ant样例
下面举一个Ant的样例,下面是Ant输出的帮助信息
ant [options] [target [target2 [target3] ...]] Options: -help print this message -projecthelp print project help information -version print the version information and exit -quiet be extra quiet -verbose be extra verbose -debug print debugging information -emacs produce logging information without adornments -logfile <file> use given file for log -logger <classname> the class which is to perform logging -listener <classname> add an instance of class as a project listener -buildfile <file> use given buildfile -D<property>=<value> use value for given property -find <file> search for buildfile towards the root of the filesystem and use it
使用Bool选项创建
Option help = new Option( "help", "print this message" ); Option projecthelp = new Option( "projecthelp", "print project help information" ); Option version = new Option( "version", "print the version information and exit" ); Option quiet = new Option( "quiet", "be extra quiet" ); Option verbose = new Option( "verbose", "be extra verbose" ); Option debug = new Option( "debug", "print debugging information" ); Option emacs = new Option( "emacs","produce logging information without adornments" );
也可以使用OptionBuilder构建选项:
Option logfile = OptionBuilder.withArgName( "file" ) .hasArg() .withDescription( "use given file for log" ) .create( "logfile" ); Option logger = OptionBuilder.withArgName( "classname" ) .hasArg() .withDescription( "the class which it to perform "+ "logging" ) .create( "logger" ); Option listener = OptionBuilder.withArgName( "classname" ) .hasArg() .withDescription( "add an instance of class as "+ "a project listener" ) .create( "listener"); Option buildfile = OptionBuilder.withArgName( "file" ) .hasArg() .withDescription( "use given buildfile" ) .create( "buildfile"); Option find = OptionBuilder.withArgName( "file" ) .hasArg() .withDescription( "search for buildfile towards the "+ "root of the filesystem and use it" ) .create( "find" );
最后一个OptionBuilder创建带有参数名称的选项:
Option property = OptionBuilder.withArgName( "property=value" ) .hasArgs(2) .withValueSeparator() .withDescription( "use value for given property" ) .create( "D" );
通过上面的方式定义的属性,可以通过CommandLine对象的getOptionProperties(“D”)方法获得。
定义阶段——创建选项
Options options = new Options(); options.addOption( help ); options.addOption( projecthelp ); options.addOption( version ); options.addOption( quiet ); options.addOption( verbose ); options.addOption( debug ); options.addOption( emacs ); options.addOption( logfile ); options.addOption( logger ); options.addOption( listener ); options.addOption( buildfile ); options.addOption( find ); options.addOption( property );
解析阶段——创建解析器
跟前面类似,创建CommandLineParser解析器,返回CommandLine对象,用于查询选项参数。
public static void main( String[] args ) { // create the parser CommandLineParser parser = new DefaultParser(); try { // parse the command line arguments CommandLine line = parser.parse( options, args ); } catch( ParseException exp ) { // oops, something went wrong System.err.println( "Parsing failed. Reason: " + exp.getMessage() ); } }
询问阶段——查询命令行参数
通过hasOption选项判断是否包含某个选项参数:
// has the buildfile argument been passed? if( line.hasOption( "buildfile" ) ) { // initialise the member variable this.buildfile = line.getOptionValue( "buildfile" ); }
创建帮助信息
一般命令行工具都有help帮助提示,即输入-h命令,就会输出所有的命令参数。CLI提供给我们快捷输出帮助信息的工具——HelpFormatter。
// automatically generate the help statement HelpFormatter formatter = new HelpFormatter(); formatter.printHelp( "ant", options );
当执行到此处时,就会输出相应的帮助信息
usage: ant -D <property=value> use value for given property -buildfile <file> use given buildfile -debug print debugging information -emacs produce logging information without adornments -file <file> search for buildfile towards the root of the filesystem and use it -help print this message -listener <classname> add an instance of class as a project listener -logger <classname> the class which it to perform logging -projecthelp print project help information -quiet be extra quiet -verbose be extra verbose -version print the version information and exit
全部代码
public class AntExample { public static void main(String[] args) { String[] arg = {"-help"}; testOption(arg); } @SuppressWarnings({ "deprecation", "static-access" }) static void testOption(String[] args){ Option help = new Option( "help", "print this message" ); Option projecthelp = new Option( "projecthelp", "print project help information" ); Option version = new Option( "version", "print the version information and exit" ); Option quiet = new Option( "quiet", "be extra quiet" ); Option verbose = new Option( "verbose", "be extra verbose" ); Option debug = new Option( "debug", "print debugging information" ); Option emacs = new Option( "emacs","produce logging information without adornments" ); Option logfile = OptionBuilder.withArgName( "file" ) .hasArg() .withDescription( "use given file for log" ) .create( "logfile" ); Option logger = OptionBuilder.withArgName( "classname" ) .hasArg() .withDescription( "the class which it to perform "+ "logging" ) .create( "logger" ); Option listener = OptionBuilder.withArgName( "classname" ) .hasArg() .withDescription( "add an instance of class as "+ "a project listener" ) .create( "listener"); Option buildfile = OptionBuilder.withArgName( "file" ) .hasArg() .withDescription( "use given buildfile" ) .create( "buildfile"); Option find = OptionBuilder.withArgName( "file" ) .hasArg() .withDescription( "search for buildfile towards the " + "root of the filesystem and use it" ) .create( "find" ); Option property = OptionBuilder.withArgName( "property=value" ) .hasArgs(2) .withValueSeparator() .withDescription( "use value for given property" ) .create( "D" ); Options options = new Options(); options.addOption( help ); options.addOption( projecthelp ); options.addOption( version ); options.addOption( quiet ); options.addOption( verbose ); options.addOption( debug ); options.addOption( emacs ); options.addOption( logfile ); options.addOption( logger ); options.addOption( listener ); options.addOption( buildfile ); options.addOption( find ); options.addOption( property ); CommandLineParser parser = new DefaultParser(); try { CommandLine line = parser.parse( options, args ); if( line.hasOption( "buildfile" ) ) { System.out.println(line.getOptionValue( "buildfile" )); } if( line.hasOption("help")){ HelpFormatter formatter = new HelpFormatter(); formatter.printHelp( "ant", options ); } }catch( ParseException exp ) { System.err.println( "Parsing failed. Reason: " + exp.getMessage() ); } } }
运行后得到下面的输出信息:
usage: ant -buildfile <file> use given buildfile -D <property=value> use value for given property -debug print debugging information -emacs produce logging information without adornments -find <file> search for buildfile towards the root of the filesystem and use it -help print this message -listener <classname> add an instance of class as a project listener -logfile <file> use given file for log -logger <classname> the class which it to perform logging -projecthelp print project help information -quiet be extra quiet -verbose be extra verbose -version print the version information and exit
如果想在输出信息中加入参数列表,也可以在printHelp加入第三个参数true,formatter.printHelp( "ant", options, true);
usage: ant [-buildfile <file>] [-D <property=value>] [-debug] [-emacs] [-find <file>] [-help] [-listener <classname>] [-logfile <file>] [-logger <classname>] [-projecthelp] [-quiet] [-verbose] [-version] -buildfile <file> use given buildfile -D <property=value> use value for given property -debug print debugging information -emacs produce logging information without adornments -find <file> search for buildfile towards the root of the filesystem and use it -help print this message -listener <classname> add an instance of class as a project listener -logfile <file> use given file for log -logger <classname> the class which it to perform logging -projecthelp print project help information -quiet be extra quiet -verbose be extra verbose -version print the version information and exit
LS样例
这个例子模拟了Linux下的命令行使用帮助:
全部代码:
public class LSExample { public static void main(String[] args) { String[] arg = new String[]{ "--block-size=10" }; testOption(arg); } static void testOption(String[] args){ CommandLineParser parser = new DefaultParser(); // create the Options Options options = new Options(); options.addOption( "a", "all", false, "do not hide entries starting with ." ); options.addOption( "A", "almost-all", false, "do not list implied . and .." ); options.addOption( "b", "escape", false, "print octal escapes for nongraphic " + "characters" ); options.addOption( OptionBuilder.withLongOpt( "block-size" ) .withDescription( "use SIZE-byte blocks" ) .hasArg() .withArgName("SIZE") .create() ); options.addOption( "B", "ignore-backups", false, "do not list implied entried " + "ending with ~"); options.addOption( "c", false, "with -lt: sort by, and show, ctime (time of last " + "modification of file status information) with " + "-l:show ctime and sort by name otherwise: sort " + "by ctime" ); options.addOption( "C", false, "list entries by columns" ); try { CommandLine line = parser.parse( options, args ); if( line.hasOption( "block-size" ) ) { System.out.println( line.getOptionValue( "block-size" ) ); } } catch( ParseException exp ) { System.out.println( "Unexpected exception:" + exp.getMessage() ); } } }
输出可以得到下面的信息:
10 usage: ls -a,--all do not hide entries starting with . -A,--almost-all do not list implied . and .. -b,--escape print octal escapes for nongraphic characters -B,--ignore-backups do not list implied entried ending with ~ --block-size <SIZE> use SIZE-byte blocks -c with -lt: sort by, and show, ctime (time of last modification of file status information) with -l:show ctime and sort by name otherwise: sort by ctime -C list entries by columns
参考
我的前一天总结
Apache Common CLI官方文档
用户点评