【问题标题】:Pass an argument that starts with '@' to jcommander将一个以“@”开头的参数传递给 jcommander
【发布时间】:2015-01-06 20:50:52
【问题描述】:

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

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

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

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

【问题讨论】:

  • 据我从 1.35 的资料来看,这似乎是不可能的。
  • 消息来源似乎表明它正在读取文件而不在其中应用 @ 语法。您确定您的文件中的 @arg 参数会出现同样的错误吗?
  • @RealSkeptic 是的,对于我列出的版本(1.32)
  • 这些是sources I'm looking at。也许您没有正确命名包含参数的文件?它应该正是@ 之后的内容,并且应该在当前工作目录或绝对路径中。
  • 我认为我应该正确地进行测试。我将文件命名为 test.arg 并在其中放置了一行 @arg。现在在运行app @test.arg 之后,我得到了同样的错误Could not read file arg: java.io.FileNotFoundException: arg (No such file or directory).

标签: java jcommander


【解决方案1】:

作为我和OP之间关于这个的聊天讨论的结果,我们得出了以下结论:

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

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

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

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

file1.txt

@file2.txt

file2.txt

@actualparameter

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

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

  1. 使用不同的命令行解析器。
  2. 修补 JCommander 源代码,以便有办法逃脱 @ 机制或要求原作者自己这样做。
  3. 作为一个组合,在任何可能以@ 开头的参数前添加一个字符,然后在我需要使用参数值时删除该字符。至少这不会创建两个额外的文件。

编辑:Jcommander 的作者修复了这个问题。

根据this pull request on Jcommander's github 的cmets,有一种新方法允许禁用@ 符号的处理。例如

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

该方法已从 1.54 版本开始添加。

【讨论】:

  • 感谢您花时间发布如此详细的答案。
  • 也感谢有关关闭行为的新选项的更新。
【解决方案2】:

完全禁用该功能

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

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

builder上也有对应的选项

对文件使用间接

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

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

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

以@开头的转义参数

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-24
    • 1970-01-01
    • 1970-01-01
    • 2012-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多