【问题标题】:The issue of * in Command line argument命令行参数中 * 的问题
【发布时间】:2011-02-12 17:11:00
【问题描述】:

我用 Java 编写了一个程序,它通过命令行参数接受输入。 我从命令行输入两个数字和一个运算符。 要将两个数字相乘,我必须输入例如5 3 *,但它并没有像写的那样工作。

为什么它不接受来自命令行的*

【问题讨论】:

  • 我删除了java标签,因为这是一个普遍的问题,与Java无关。您可以从不发生通配的某个地方(例如,另一个 Java 程序)启动您的 Java 程序而不会出现问题。
  • 您使用的是什么操作系统?执行的具体命令是什么?
  • 如果从 cygwin bash shell 运行,以下解决方案不起作用(引用或转义星号),因为 jvm 在内部使用尾随星号,尽管触发它的情况尚不清楚(到我,至少)。请参阅下面 Arno 的条目。

标签: java command-line-arguments wildcard glob


【解决方案1】:

这是因为* 是一个shell 通配符:它对shell 有特殊含义,它在将其传递给命令之前对其进行扩展(在本例中为java)。

由于您需要文字 *,因此您需要将其从 shell 中转义。转义的具体方式因你的 shell 而异,但你可以尝试:

java ProgramName 5 3 "*"

或者:

java ProgramName 5 3 \*

顺便说一句,如果您想知道 shell 对 * 的作用,请尝试将 String[] args 的内容打印到您的 main 方法中。您会发现它将包含您目录中文件的名称。

如果您需要将一些文件名作为命令行参数传递,这会很方便。

另见

  • Wikipedia: glob

    例如,如果一个目录包含两个文件,a.logb.log,那么命令 cat *.log 将被 shell 扩展为 cat a.log b.log

  • Wikipedia: Escape character

    在 Bourne shell (sh) 中,星号 (*) 和问号 (?) 字符是通过通配符扩展的通配符。如果没有前面的转义字符,* 将扩展为工作目录中不以句点开头的所有文件的名称,当且仅当存在此类文件时,否则 * 保持未扩展。因此,要引用一个字面上称为 "*" 的文件,必须告诉 shell 不要以这种方式解释它,在它前面加上一个反斜杠 (\)。

【讨论】:

  • 为了完整起见,并且由于 OP 没有提及任何特定的操作系统,请注意,在 Windows 中,通配是应用程序的责任,而不是外壳。它通常由应用程序的运行时库处理。
  • 事实证明,Windows jvm 在某些情况下会在内部执行自己的 globbing,请参阅 stackoverflow.com/questions/37037375
【解决方案2】:

尝试在* 周围加上"*" 这样的引号。星号是命令行中的保留符号。

【讨论】:

    【解决方案3】:

    * 在 shell 解释器中具有特殊含义。如何从字面上获得 * 取决于您使用的 shell 解释器。对于 Bash,您应该在 * 周围加上单引号,即 '*',而不是像 "*" 这样的双引号。

    【讨论】:

      【解决方案4】:

      在 MS WINDOWS 下不太正确:“java.exe”使用通配符默默地扩展命令行参数

      • *
      • ?
      • [abc]

      ,但只在最后一个组件中,所以

      a/*/*
      

      不像你想象的那样工作。

      它也忽略条目“。”和“..”,但尊重其他以“.”开头的文件名。

      为了避免误解:如果我用 PROCEXP 查看正在运行的 JAVA 进程的命令行,我会看到 unexpanded args!

      我发现没有办法解决这个问题。换句话说:只要你在当前目录下至少有一个文件或目录,“java Calc 3 * 7”就行不通!

      这非常丑陋,而且似乎一直存在于所有 JRE 版本中,包括 Java 8。

      有人知道如何禁用 Java 讨厌的命令行扩展吗?

      【讨论】:

      • 我同意,这个特性可能很讨厌,但如果 java 命令行工具相对于操作系统无关,这是一个实际的要求。但是,似乎没有任何 system.property 可以禁用它,这使它变得令人讨厌(叹气)。
      • 顺便说一句,您可以在 cmd.exe 会话中对星号进行双引号,它会执行您所期望的操作,但是如果从 cygwin BASH 会话中运行,似乎没有任何方法做同样的事情。奇怪的部分是我已经验证问题发生在java中的某个地方,而不是在shell环境中(如你所说)。在这里查看我的笔记:stackoverflow.com/questions/37037375
      • 无论转义/引用如何,这个问题也会出现从 PowerShell 调用
      【解决方案5】:

      使用single quotes:

      java FooBar 5 3 '*'
      

      这适用于大多数流行的 shell(包括 bash 和 ksh)。

      【讨论】:

        【解决方案6】:

        扩展@Arno Unkrig 的回答:

        在 Windows 上,某些 JVM 肯定会扩展“*”字符,而不是 shell 扩展路径。您可以通过编写一个打印出参数的小型 Java 程序来确认这一点:

        public class TestArgs {
            public static void main(String[] args) {
                for (int i = 0; i < args.length; i++) {
                    System.out.println("Arg " + i + ": " + args[i]);
                }
            }
        }
        

        好消息是,有一个解决方法!您可以像这样使用@filename 作为JVM 的参数:

        java @args.txt 其中args.txt 是一个文本文件,其中包含每一行的参数。示例内容:

        TestArgs
        *
        

        这相当于使用两个参数TestArgs* 调用java。最重要的是,* 在使用@filename 方法包含时不会展开。我可以从this page 找到详细信息。

        【讨论】:

          猜你喜欢
          • 2015-10-17
          • 2019-06-21
          • 2015-02-23
          • 2011-11-11
          • 1970-01-01
          相关资源
          最近更新 更多