|
如果曾经用过unix或曾经用过C编程,getopts一定不陌生,CLI跟getopts一样
,是一个用来处理命令行参数或选项的Java API。
其实,相对而言对命令行的处理并不复杂,但如果采用一个能用的命令行处理接口,可能更容易让用户接
受你的命令行设置。而对Java程序而言,似乎用XML文件来进行配置更为常见,这大概是java更多地被用于web
应用编程有关。
如果有兴趣,就继续往下看。
为了不致引起混乱,先说明一下几个术语。假定下面是某次执行命令cmd时的情况, $cmd -a -b c -d e=f g ,这里:- 整个” cmd -a -b c -d e=f g”被称为命令行
- “-a -b c -d e=f g”被称为命令行参数,与命令行的差别就是没有命令“cmd”。现实中,在不引
起混乱的情况下,也将命令行参数简称为“命令行”
- “-a”、“-b c”、“-d e=f”都是选项
(option),此处恰好代表了不同的常见类型
- ”c”称为“-b”的参数,同理”e=f”是”-d”的参数。
三个阶段 命令行的处理过程包括:定义、解析和查询三个阶段。下面就依次讨论每一个阶段
,并说明CLI是如何实现的。
CLI处理命令行的思路是这样的:首先将程序要接收的选项及选项的要求,放入一个Options对象,然后将
此对象及命令行字符串一起作参数传递给一个Parser对象的parse解析函数,解析函数将Options对象的内容与
命令行进行对照解析,将结果保存在CommanLine对象中,最后用户的程序调用CommandLine对象的hasOption()
方法来查询某个选项是否存在,如果此选项有参数则可用getOptionValue取回它的参数值。
定义阶段
每个命令行都会定义一些选项,以用它们定义应用程序的用户交互界面。CLI使用Options类,作为一容器
来存放Option实例。在CLI中创建Option实例的方法有两种,一是通过构造函数constuctors,另一个是通过
Options中工厂(factory)方法.
该阶段的结果,是一个Options实例。
解析阶段
该阶段是那些通过命令行传递给应用程序的文本信息被实际进行处理的阶段。解析器根据定义阶段的定义
的规则(选项及要求)来处理命令行文本信息。CommandLineParser 的parse方法,接收一个Options实例和一个
String[]作为参数,返回一个CommandLine实例 .
该阶段的结果,是一个 CommandLine 实例.
查询(Interrogation)阶段
在该阶段,应用程序查询CommandLine,根据一些布尔选项的值决定执行哪些子程序,并根据选项的值来取
得提供给应用程序的数据。这个阶段,由用户的代码实现。CommanLine提供一些查询的方法供用户代码使用。
例子
例1
假定有一个DateApp程序,用来显示日期,如果给它一个“-t”选项,它可以同时把时间也显示出来。这
个”-t”选项,是个布尔选项,也就是说,这种选项在命令行中出现与否,直接表示了选项值的真/假,或者假
/真。DateApp的命令行处理过程如下:...
// create Options object
Options options = new Options();
// add t option
options.addOption("t", false, "display current time");
...
CommandLineParser parser = new PosixParser();
CommandLine cmd = parser.parse( options, args);
...
if(cmd.hasOption("t")) {
// print the date and time
}else {
// print the date
} 此中的addOption方法接收三个参数,第一个是选项名,第二个用是指明是否为布尔选项(即此选项有
无参数),第三个是对该参数的解释。
CLI能自动生成命令的使用说明(Usage),第三个参数就是供生成使用说明之用的。
现在DateApp程序的功能有了扩展,它可以以某个国家本地的格式显示日期(及时间),这就需要一个新的
先项”-c country”,来指明国家的信息。这类参数的处理方法如下:...
// add c option
options.addOption("c", true, "country code");
...
// get c option value
String countryCode = options.getOptionValue("c");
if(countryCode == null) {
// print default date
}else {
// print date for country specified by countryCode
} 此中的getOptionValue,当选项C的参数值在命令行没有提供时,则返回null.
例2
下面,以ant的命令行处理为例,说明其它的Option实例生成方法。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 use given file for log
-logger the class which is to perform logging
-listener add an instance of class as a project listener
-buildfile use given buildfile
-D= use value for given property
-find search for buildfile towards the root of the filesystem and use it
其中,布尔选项的定义如下: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( "file" );
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" ); 以buildfile为例
说明一下,“=”前面的buildfile是实例(或说变量)名字,可以任意指定,建议与选项名相同;
withArgName中的”file”是选项buildfile的参数的名字,在显示使用说明时会将此名字显示出来,而实际运
行命令是用户会输入具体的值(如具体某个文件的名字);create()中的”buildfile”是选项的名字,不能搞
错,如果错成别的名字,则就成了别的名字的选项了。
Java属性的选项定义如下:Option property = OptionBuilder.withArgName(
"property=value" ).hasArgs().withValueSeparator().withDescription( "use value for given property"
).create( "D" ); 生成Options实例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 ); 创建解析器public static void main( String[]
args ) {
// create the parser
CommandLineParser parser = new GnuParser();
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() );
}
} 查询选项值// has the buildfile argument been passed?
if( line.hasOption( "buildfile" ) ) {
// initialise the member variable
this.buildfile = line.getValue( "buildfile" );
}
需要说明的是,上面的例子中,对于一个选项出现两次时的情况,第二次的值都被忽略了,除非你在生成
Option时调用过hasArgs()(不是hasArg)。如果程序中要对同一个选项出现的次数不同而采取不同的执行过程时
,可以用Option的getValues()返回一个String[],里面存放着所有的参数值,也可以用getValue()以一个整数
值作参数指定返回第几个参数值(对于Java属性类型的选项,“=”前后的两个串CLI是当作两个参数值来处理
的)。
对于非定义的选项,命令中出现的其它字符串,可以用CommandLine的getArgs()返回一个存放它们的
String[].
另外,cli能根据你对选项的定义,生成用法说明,代码如下:// automatically
generate the help statement
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp( "ant", options );
附:Option类的属性表
| 属性名 | 类型 | 描述 | | opt
| java.lang.String | Option.的唯一标志串 | | longOpt
| java.lang.String | 别名及描述性的唯一标志串 | | description
| java.lang.String | Option的功能描述 | | required | boolean
| 一个是否要求该Option必须在命令行出现的标志 | | multipleArgs
| boolean | 该option是否有多参数值的标志 | | arg | boolean
| 该option是否有参数的标志 | | args | boolean | 该option是否有
不只一个参数的标志 | | optionalArg | boolean | 该option的参数是否是可
选的(即不是必须的) | | argName | java.lang.String | 在显示命令用法时
显示的参数的名子 | | valueSeparator | char | 参数值串的分隔符,连接着
多个参数值的各个参数。如,如果分隔符是“,”且参数串为“a,b,c”则选项有三个参数值a,b和
c. | 注:不知什么原因,API文档包括CLI站点的文档中的例子,有比较多的疏漏
,建议参考上面的代码进行学习。
原作者:Hilton
来 源:http://hedong.3322.org
|