5

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

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

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

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

4

2 回答 2

7

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

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

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

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

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

文件1.txt

@file2.txt

文件2.txt

@actualparameter

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

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

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

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

根据Jcommander 的 github 上对此拉取请求的评论,有一种新方法允许禁用对@标志的处理。例如

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

从 1.54 版开始添加该方法。

于 2014-11-10T16:01:51.493 回答
0

完全禁用该功能

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

  • jc.setExpandAmpersat(false)(如本答案所述)
  • 或,jc.setExpandAtSign(false) (在某些版本中)

builder上也有对应的选项

对文件使用间接寻址

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

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

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

以 @ 开头的转义参数

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

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

于 2021-07-14T08:42:05.200 回答