Apache--common-cli工具解析

栏目: Java · 发布时间: 6年前

内容简介:无意中发现了命令行一般有清单1:-与–区别

无意中发现了 apache-common-cli 这款小而美的命令行解析工具,顿时充满了兴趣,该篇文章分析其实现原理。

命令行格式

命令行一般有 --- 的参数形式,不管之前的Unix,BSD,GNU等如何定义,按照现在大众认知一般认为 - 表示缩写命令,方便快速输入, -- 表示全命令,主要用于完整描述该命令。

清单1:-与–区别

ls -a    ==     ls --all
ls -A    ==    ls --almost-all

当然也有另类,比如java,对于这种忽略吧。。。

清单2:Java奇怪的命令行

java -v 错误
java --version 错误
java -version 正确

common-cli

apache-common-cli 解析命令行主要使用了三个组件:

  1. Option:描述程序所能接收的命令
  2. CommandLineParser:解析器,能够解析用户输入的参数
  3. CommandLine:解析结果

Option

一个 org.apache.commons.cli.Option 代表着程序的一个参数,其承载着该参数的配置信息,比如短命令格式,长命令格式,是否必须,参数类型等等,因此该类需要有很多字段来描述这些属性,如下图所示:

Apache--common-cli工具解析

属性多带来的是初始化的繁琐,因此该类的设计使用了Builder设计模式,Builder设计模式本质上是一种特殊的工厂,按照指定的流水线生产对象,最后在build()前对对象进行检查,保证产出合格对象。

一款软件往往有着众多的命令,为了更加简化该方式, common-cli 使用 org.apache.commons.cli.Options 类提供更加友好的创建方式, Options 类为 Option 的集合,提供了众多方法对 Option 的创建封装,方便开发者使用。

Apache--common-cli工具解析

因此在使用 common-cli 时可以如下形式,灵活的选择需要的初始化方式。

清单1:命令初始化

Options options = new Options()
      .addOption("a", "all", false, "ls -a")
      .addOption("R", "recursive", false, "ls -R")
      .addOption(Option.builder("r")
          .longOpt("reverse")
          .hasArg(false)
          .desc("ls -r")
          .build());

CommandLine

org.apache.commons.cli.CommandLine 是经过 Parse 解析后产出的结果,主要包含已识别命令集合以及未识别的命令集合。

清单2:CommandLine结构

/** the unrecognized options/arguments */
private final List<String> args = new LinkedList<String>();

/** the processed options */
private final List<Option> options = new ArrayList<Option>();

CommandLineParser

解析器是 common-cli 的核心,目前官方推荐使用 org.apache.commons.cli.DefaultParser 作为实现类,从该实现类的结构中可以看出其并不是一个线程安全的实现,解析过程中会将很多中间状态保存在全局变量中,主要解析方法为 CommandLine parse(final Options options, final String[] arguments) 方法,解析流程看下来不是很复杂,大致为匹配到相应场景就去尝试,尝试失败再使用其他场景,因此该部分会针对一些问题进行分析。

命令值如何解析?

参数的形式主要有以下几种,匹配规则也是到对应的 Option 时,尝试去获取后面的参数。

-SV  # 如果S命令有值则直接把后面的字符串当成值.
-S V  # 设置中间状态,下一轮匹配则附加上值
-S=V # 等号后面的为值
-S1S2 V # 该形式要求S1必须是无参命令,S2参数则与上述匹配类似
-SV1=V2 # 这种类似jvm参数 -DskipTest=true,忽略-D与上述类似

混合命令如何解析?

所谓的混合命令比如 ls -la 实际上为 ls -l -a ,对于该命令解析 common-cli 会把参数拆分成单个字符,然后遍历匹配一遍,一旦发现匹配则加入到匹配集合中。

protected void handleConcatenatedOptions(final String token) throws ParseException{
       for (int i = 1; i < token.length(); i++){
           // 混合命令会拆分成字符
           final String ch = String.valueOf(token.charAt(i));
           // 对每一个字符进行匹配
           if (options.hasOption(ch))
           {
               // 匹配成功的加入到commandLine中
               handleOption(options.getOption(ch));

               if (currentOption != null && token.length() != i + 1)
               {
                   // add the trail as an argument of the option
                   // 获取参数值
                   currentOption.addValueForProcessing(token.substring(i + 1));
                   break;
               }
           }
           else
           {
               handleUnknownToken(stopAtNonOption && i > 1 ? token.substring(i) : token);
               break;
           }
       }
   }

如何线程安全的使用?

Parser 类并非线程安全的实现,在解析过程中中间状态存储,以及结果存储都需要使用共享变量形式传递,如果想要线程安全的使用,可以使用 Thread Specific Storge模式 ,该模式的解决思路是不共享单个变量,共享一堆变量,每一个变量被获取后只与一个线程绑定。

总结

apache的项目规范就是好,无论是代码注释,还是单测都十分完善,哎,上班能遇到这样的代码多好。

读书笔记 --正则闯关记录


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

垃圾回收的算法与实现

垃圾回收的算法与实现

中村成洋、相川光 / 丁灵 / 人民邮电出版社 / 2016-7-1 / 99.00元

★ Ruby之父Matz作推荐语:上古传承的魔法,彻底揭开垃圾回收的秘密! ★ 日本天才程序员兼Lisp黑客竹内郁雄审校 本书前半介绍基本GC算法,包括标记-清除GC、引用计数、复制算法的GC、串行GC的算法、并发GC的算法等。后半介绍V8、Rubinius、Dalvik、CPython等几种具体GC的实现。本书适合各领域程序员阅读。一起来看看 《垃圾回收的算法与实现》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码