超强命令行解析工具 Apache Commons CLI 各个模块阅读

本文介绍了Java中处理命令行参数的Option类、OptionGroup类和Options类的定义、方法以及解析过程,包括CommandLineParser接口和DefaultParser的使用,以及HelpFormatter类用于打印帮助信息的示例。
摘要由CSDN通过智能技术生成

这里会介绍各个模块相关类及方法

定义阶段

Option类

一个Option类就是一个命令行选项对象
属性 :

private final String option; // 短选项名称
private String longOption; // 长选项名称
private String argName; // 输入参数的一个提示信息,一般会是参数的类型,比如string,int,boolean等
private String description; // 描述信息
private boolean required; // 选项是否必须存在
private boolean optionalArg; // 参数值可选,比如可以是 -f filepath 或者直接 -f
private int argCount; // 设置接收参数的个数,有时候一个选项可能会接入多个参数值,一般都是一个
private Class<?> type; // 告诉接收参数的数据类型
private List<String> values; // 参数值列表,解析后的
private char valuesep; // values的分隔符

构造方法 :

// 短选项,长选项,是否含参数,选项描述
public Option(String option, String longOption, boolean hasArg, String description)
//短选项,描述  (longOption=null,hasArg=false)
public Option(String option, String description)
//短选项,是否含参数,选项描述 (longOption=null)
public Option(String option, boolean hasArg, String description)
// 通过Builder类来构造 如下 : 
Option.builder()
        .longOpt("global-config")
        .hasArg()
        .desc("Path of the global configuration file for Flink CDC pipelines")
        .build();

方法 :

// 对比两个对象是否相等,内存地址或者对比longOption和option都一样的话返回true
public boolean equals(Object obj)
// 将选项复制,深拷贝
public Object clone()
// 获取opiton 如果为null,就返回longOption
String getKey()
// 其余public方法都是些set get方法

OptionGroup类

OptionGroup类可以将一组选项组织起来,确保用户只能选择其中的一个选项,一般是用在命令行中选项互斥的场景.
可以使用 addOption(String Option) 方法来添加group

Options类

Options类是存放Option类的容器
属性 :

// key 是短选项,value 是Option类
private final Map<String, Option> shortOpts = new LinkedHashMap();
// key 是长选项,value 是Option类
private final Map<String, Option> longOpts = new LinkedHashMap();
// 选项是否必须存在的列表
private final List<Object> requiredOpts = new ArrayList();
// Option组
private final Map<String, OptionGroup> optionGroups = new LinkedHashMap();

常用的方法 :

// 添加选项
public Options addOption(Option opt)
// 同Option类
public Options addOption(String opt, boolean hasArg, String description)
// 同Option类
public Options addOption(String opt, String description)
// 同Option类
public Options addOption(String opt, String longOpt, boolean hasArg, String description)
// 添加OptionGroup(一般用于互斥选项)
public Options addOptionGroup(OptionGroup group)
// 添加必选选项
public Options addRequiredOption(String opt, String longOpt, boolean hasArg, String description)
// 获取长选项中匹配的选项,相等的话就返回一个值,或者以opt开头的多个值
public List<String> getMatchingOptions(String opt)
// 根据选项名获取Option,优先取短选项,短的取不到就取长选项
public Option getOption(String opt)
// 判断是否包含这个长选项
public boolean hasLongOption(String opt)
// 判断是否包含短选项
public boolean hasShortOption(String opt)
// 判断是否包含短选项或者长选项
public boolean hasOption(String opt)
// 帮助信息list
List<Option> helpOptions()

解析阶段

CommandLineParser接口

CommandLIneParser 是一个解析接口,有多个实现类,一般用DefaultParser实现类即可,其他的都弃用了,传入两个参数,一个是定义阶段构建的Options对象,还有一个就是main方法的String args[]数组,第三个参数是个布尔类型,如果为true,则无法识别的参数将停止解析,其余参数将添加到CommandLine的args列表中。如果为false,则无法识别的参数将触发ParseException。默认是false

public interface CommandLineParser {
    CommandLine parse(Options options, String[] arguments) throws ParseException;

    CommandLine parse(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException;
}

DefaultParser实现类

这个类的作用就是根据Options 和 main方法传入的args数组解析成一个CommandLine对象,方便之后处理.

CommandLineParser parser = new DefaultParser();
CommandLine cmd = parser.parse(options, args);

具体是如何解析的呢?
具体来看一个核心的解析方法即可
DefalultParser的parse方法

public CommandLine parse(final Options options, final String[] arguments, final Properties properties, final boolean stopAtNonOption)
        throws ParseException {
        this.options = options;
        this.stopAtNonOption = stopAtNonOption;
        skipParsing = false;
        currentOption = null;
        expectedOpts = new ArrayList<>(options.getRequiredOptions());

        // clear the data from the groups
        for (final OptionGroup group : options.getOptionGroups()) {
            group.setSelected(null);
        }

        cmd = new CommandLine();

        //  这个地方就是核心的解析方法,会将main方法的入参挨个遍历,然后转换成CommandLine对象
        if (arguments != null) {
            for (final String argument : arguments) {
                handleToken(argument);
            }
        }

        // check the arguments of the last option
        checkRequiredArgs();

        // add the default options
        handleProperties(properties);

        checkRequiredOptions();

        return cmd;
    }

核心处理方法 handleToken(String arg)

    private void handleToken(final String token) throws ParseException {
        currentToken = token;

        if (skipParsing) {
            cmd.addArg(token);
        } else if ("--".equals(token)) {
            skipParsing = true;
        } else if (currentOption != null && currentOption.acceptsArg() && isArgument(token)) {
            currentOption.addValueForProcessing(stripLeadingAndTrailingQuotesDefaultOn(token));
        } else if (token.startsWith("--")) {
            handleLongOption(token);
        } else if (token.startsWith("-") && !"-".equals(token)) {
            handleShortAndLongOption(token);
        } else {
            handleUnknownToken(token);
        }

        if (currentOption != null && !currentOption.acceptsArg()) {
            currentOption = null;
        }
    }

大概的处理流程如下
比如我们用如下一个命令行

java Test -i /input/path -o /output/path

到java的args种会生成一个string数组,如下

["-i","/input/path","-o","ouput/path"]

parse方法的如下代码会遍历上面这个数组

        if (arguments != null) {
            for (final String argument : arguments) {
                handleToken(argument);
            }
        }

如果遇到–或者-开头的字符串就会将其这个字符串的–或者-去掉,然后查询Options中是否有,有的话就添加到CommandLine的Options中,然后将currentOption记录成当前的Option,接着处理下一个字符串/input/path,这个字符串不是-或者–开头的,那么就会被currentOption调用addValueForProcessing方法,将其写入到Option的values属性中,以此类推

处理阶段

CommandLine类

通过DefaultParser类将Options和args转换成了一个CommondLine对象,这个对象就是可以方便的来处理参数了
属性 :

// 未识别的选项或者参数
private final List<String> args = new LinkedList<>();
// 识别到的选项及参数
private final List<Option> options = new ArrayList<>();

常用方法

// 根据Option获取它的参数值
public String getOptionValue(final Option option)
// 有的值是多个参数,获取参数列表
public String[] getOptionValues(final Option option)
// 是否包含该选项
public boolean hasOption(final Option opt)

HelpFormatter类

一般我们在用-h或者–help的选项的时候就可以打印帮助信息,这个类就是实现这一效果的
例子🌰

//实例代码 : 
  Options options = new Options();
  options.addOption(OptionBuilder.withLongOpt("file").withDescription("The file to be processed").hasArg().withArgName("FILE").isRequired().create('f'));
  options.addOption(OptionBuilder.withLongOpt("version").withDescription("Print the version of the application").create('v'));
  options.addOption(OptionBuilder.withLongOpt("help").create('h'));
 
  String header = "Do something useful with an input file\n\n";
  String footer = "\nPlease report issues at http://example.com/issues";
 
  HelpFormatter formatter = new HelpFormatter();
  formatter.printHelp("AntgCode", header, options, footer, true);

输出结果

执行结果如下 : 
  usage: AntgCode -f <FILE> [-h] [-v]
  Do something useful with an input file
 
   -f,--file <FILE>   The file to be processed
   -h,--help
   -v,--version       Print the version of the application
 
  Please report issues at http://example.com/issues
  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Antgeek

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值