传递一个以' @'开头的论点对jcommander

时间:2014-11-10 14:09:11

标签: java jcommander

我正在使用JCommander(版本1.32)来解析传递给java应用程序的命令行参数(让我们称之为app)。我遇到的问题是我需要传递的其中一个参数以@开头,可以看出here @有一个特殊的语法。因此,使用app @arg调用应用程序失败并显示

  

无法读取文件arg:java.io.FileNotFoundException:arg(没有这样的文件或目录)。

通过阅读这些信息,我尝试将我的参数放在一个文件中,但显然“@语法”是递归的,因此,即使我将@arg放在一个文件中,我的程序也会因同样的错误而失败。

有没有办法将以@开头的参数传递给使用jcommander的程序?有没有办法禁用@语法?

2 个答案:

答案 0 :(得分:5)

由于OP和我之间的聊天讨论,我们得出以下结论:

JCommander调用自身,作为解析命令的方式的一部分 - 每个子命令结构都有自己的参数定义。

在顶层,它展开@ -parameter并创建一个包含文件内容的新参数列表。

然后,当它自己调用时,它再次解析该参数列表,因此再次扩展以@开头的任何参数。

幸运的是,它似乎只会这样做一次,所以它不是完全递归的。因此,任何想要传递以@开头的参数的人的解决方案是使用两个间接。也就是说,创建两个文件:

FILE1.TXT

@file2.txt

FILE2.TXT

@actualparameter

然后在命令行上使用@file1.txt

所以这是一种可行的解决方法。就个人而言,我对创建这样的额外文件并不太满意,我建议使用其他三种解决方案之一:

  1. 使用其他命令行解析器。
  2. 修补JCommander来源,以便有办法逃脱@机制或让原作者自己这样做。
  3. 作为kludge,将字符添加到可能以@开头的任何参数,然后在需要使用参数值时删除该字符。至少这不会创建两个额外的文件。
  4. 编辑:Jcommander的作者解决了这个问题。

    根据对this pull request on Jcommander's github的评论,有一种新方法可以禁用@符号的处理。 E.g。

    JCommander jc = new JCommander(params);
    jc.setExpandAmpersat(false);
    

    从1.54版开始添加了该方法。

答案 1 :(得分:0)

完全禁用该功能

您可以通过以下方式禁用 @ 参数的扩展:

  • jc.setExpandAmpersat(false)(如 in this answer 所述)
  • OR , jc.setExpandAtSign(false)(在某些版本中)

builder上也有相应的选项

对文件使用间接

如果您在命令行解析中绝对依赖 @,并且您希望您的用户需要传递以 @ 开头的文件名或其他参数,您可以询问他们使用额外的文件使用间接。

例如将文件名 @foo 传递给 --file,将 @foo 写在文本文件的单行上,然后通过 --file @textfile 传递该文件。扩展不是递归的。

这并不适用于所有情况。但你可以说服自己这是可以接受的。

以@开头的转义参数

应该注意的是,JCommander 仅在 start 参数时扩展 @。知道这一点,并假设您已经对程序中的参数解析有了一些控制,您可以单独保留 JCommander 默认行为,但要求用户使用转义字符前缀明确禁用每个参数。

例如您可以建立一个约定,如果用户希望在命令行上传递文件名“@foo”(或者说,twitter 句柄),他们可以使用反斜杠或空格作为前缀:--file " @foo" 或 {{ 1}}。这将阻止 JCommander 的自动扩展,但随后您的代码需要在进一步处理参数之前检测并去除该额外字符。