【问题标题】:How to get Apache CLI to handle double-dash?如何让 Apache CLI 处理双破折号?
【发布时间】:2012-02-11 14:50:39
【问题描述】:

我查看了文档,但看不到如何让 Apache Commons CLI 处理通常会终止选项处理的双连字符“选项”。

考虑以下具有“-opt”选项的命令行,该选项可以采用未指定的可选参数:

MyProgram -opt -- param1 param2

在这种情况下,我希望该选项最终没有参数,但 Apache 返回“--”作为参数。如果该选项允许多个参数,则部分或全部参数将作为参数返回。

这里是说明问题的示例代码:

package com.lifetouch.commons.cli;

import java.util.Arrays;
import org.apache.commons.cli.*;

public class DoubleHyphen {
  private static Options options = new Options();

  public static void main(String args[]) {
    // One required option with an optional argument:
    @SuppressWarnings("static-access")
    OptionBuilder builder = OptionBuilder.isRequired(true).
            withDescription("one optional arg").
            withArgName("optArg").hasOptionalArgs(1);
    options.addOption(builder.create("opt"));

    // Illustrate the issue:
    doCliTest(new String[] { "-opt"} );
    doCliTest(new String[] { "-opt", "optArg", "param"} );
    doCliTest(new String[] { "-opt", "--", "param"} );
    // What I want is for the double-dash to terminate option processing.
    // Note that if "opt" used hasOptionalArgs(2) then "param" would be a second
    // argument to that option (rather than an application parameter).
  }

  private static void doCliTest(String[] args) {
    System.out.println("\nTEST CASE -- command line items: " + Arrays.toString(args));

    // Parse the command line:
    CommandLine cmdline = null;
    try {
        CommandLineParser parser = new GnuParser();
        cmdline = parser.parse(options, args); // using stopAtNonOption does not help
    } catch (ParseException ex) {
        System.err.println("Command line parse error: " + ex);
        return;
    }

    // Observe the results for the option and argument:
    String optArgs[] = cmdline.getOptionValues("opt");
    if (null == optArgs) {
        System.out.println("No args specified for opt");
    } else {
        System.out.println(optArgs.length + " arg(s) for -opt option: " +
                Arrays.toString(optArgs));
    }

    // Observe the results for the command-line parameters:
    String tmp = Arrays.toString(cmdline.getArgList().toArray());
    System.out.println(cmdline.getArgList().size() +
            " command-line parameter(s): " + tmp);
  }
}

【问题讨论】:

  • 您使用的是最新的 Apache Commons CLI 1.2 版本吗?
  • 那么下面的PosixParser 应该可以工作。参见PosixParser.java 源代码:它确实处理--(参见第182 行的private void processNonOptionToken(String value, boolean stopAtNonOption))。
  • GnuParser 和 PosixParser 都不能正确处理 -- 选项,尤其是当它出现在可选参数的位置时。命令行 "-a -- -b" 将 -- 作为 -a 选项的参数,而 -b 始终被视为选项(而不是参数)。这与 stopAtNonOption 设置无关。我上面的测试代码可以很容易地说明这一点。
  • 您可以使用OptionBuilder.withValueSeparator() 来防止该问题吗?这样,可选参数必须通过= 与选项分开,这样解析器就不会混淆。如果等号不合适,您还可以使用 OptionBuilder.ValueSeparator(char sep) 指定自定义字符。我知道这不是您想要实现的目标,但它可能是一个可行的解决方法。
  • 这将彻底改变选项及其参数的定义,并破坏呈现给我的用户的合同。当前正在使用以空格分隔的选项。不过,这可能是一种对其他人有用的方法。

标签: java command-line-interface apache-commons apache-commons-cli


【解决方案1】:

为了将特殊标记 -- 作为选项终止符处理,您必须使用 POSIX 解析器。

使用

CommandLineParser parser = new PosixParser();

而不是

CommandLineParser parser = new GnuParser();

【讨论】:

  • 如我的 OP cmets(上)所述,简单地切换到 PosixParser 并不能解决问题。
  • 您是否尝试过同时使用truefalse stopAtNonOption 选项?如果这没有帮助,那么 Apache Commons CLI 不符合 POSIX Conventions for Command Line Arguments,我将自己提交错误报告
  • 是的。对于 GnuParser 或 PosixParser,stopAtNonOption 值无关紧要。我上面的测试程序可以很容易地证明这一点。观察第三个测试用例的结果永远不会改变。为了强化这一点,为“-opt -- -opt2”添加一个测试用例。
  • 还要注意,将 stopAtNonOption 更改为 true 确实会改变这样的命令行的处理方式:“-opt1 param1 arg1 -opt2 arg2 arg3”。我不想彻底改变选项解析语义,我只想正确处理 -- 。
  • 我正在授予赏金,因为 Unai Vivi 确实在这方面工作,我很欣赏这种努力。但我没有接受答案,因为我仍然没有解决方案让 Apache Commons CLI 1.2 正确处理双破折号。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-06
  • 2013-05-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多