Apache Commons CLI选项解析器能否忽略未知的命令行选项?

21

我正在编写一个Java应用程序,它接受命令行参数,并使用带有GnuParser的Apache Commons CLI进行处理。由于一些不重要的原因,我希望它在遇到未知的命令行选项时静默地忽略它们,而不是抛出ParseException,但我没有找到这样做的方法。我看到GnuParser.parse()上有一个stopAtNonOption布尔选项,但我想要更像是ignoreAtNonOption,它会在遇到未知标记后继续处理选项。

我可以实现自己的解析器来实现这一点,但我很惊讶没有内置此功能,所以我想在走这条路之前先进行检查。

下面是我所说的示例代码:

try {
  CommandLine commandLine = parser.parse(options, args);
  // stopAtNonOption set to true (below) is also not what I want
  // CommandLine commandLine = parser.parse(options, args, true);
} catch (ParseException e) {
  LOG.error("error parsing arguments", e);
  throw new RuntimeException(e);
}
4个回答

29

这个对我有效(也可以派生出其他解析器):

public class ExtendedGnuParser extends GnuParser {

    private boolean ignoreUnrecognizedOption;

    public ExtendedGnuParser(final boolean ignoreUnrecognizedOption) {
        this.ignoreUnrecognizedOption = ignoreUnrecognizedOption;
    }

    @Override
    protected void processOption(final String arg, final ListIterator iter) throws     ParseException {
        boolean hasOption = getOptions().hasOption(arg);

        if (hasOption || !ignoreUnrecognizedOption) {
            super.processOption(arg, iter);
        }
    }

}

8
太美了,谢谢!顺便说一下,这应该是对于任何 API 设计者的一个提示,为什么你绝对不想让你的 API 类是 final 的。为什么呢?因为你不够聪明,无法想象客户端代码想要重复使用你的东西的所有方式。 - James E. Ervin
我已经为BasicParser做了同样的事情。效果非常好!应该被添加到cli API中。 - Dudi
1
这个现在已经过时了 :(. - Decoded
@JamesE.Ervin 说得好,关于 final 的问题,但是你可以使用委托模式来代替继承:https://en.wikipedia.org/wiki/Delegation_pattern - thetoolman
1
如果我想在解析后的运行时访问被忽略的选项怎么办? - Aleksandr Kravets

8

如评论中所提到的,原先被接受的解决方案已经不再适用,因为processOption方法已被弃用并删除。

以下是我的解决方案:

public class ExtendedParser extends DefaultParser {

    private final ArrayList<String> notParsedArgs = new ArrayList<>();

    public String[] getNotParsedArgs() {
        return notParsedArgs.toArray(new String[notParsedArgs.size()]);
    }

    @Override
    public CommandLine parse(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException {
        if(stopAtNonOption) {
            return parse(options, arguments);
        }
        List<String> knownArguments = new ArrayList<>();
        notParsedArgs.clear();
        boolean nextArgument = false;
        for (String arg : arguments) {
            if (options.hasOption(arg) || nextArgument) {
                knownArguments.add(arg);
            } else {
                notParsedArgs.add(arg);
            }

        nextArgument = options.hasOption(arg) && options.getOption(arg).hasArg();
        }
        return super.parse(options, knownArguments.toArray(new String[knownArguments.size()]));
    }

}

与Pascal提出的解决方案相比,它还检查带参数的选项,并将未解析的参数保留在单独的列表中。

1

使用Commons CLI无法实现此功能。但是,如果您提供更多有关您的用例的详细信息,可能会有另一种方法来实现您期望的结果。


0

我是一个非常糟糕的开发者,而且我这样做是为了破坏代码:

public class EasyPosixParser extends PosixParser {
    @Override
    protected void processOption(String arg, ListIterator iter) throws ParseException
    {
        try {
            super.processOption(arg, iter);
        } catch (ParseException e) {
            // do nothing
        }
    }
}

在你的主要代码中,你这样写:

    CommandLineParser commandlineParser = new EasyPosixParser();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接