命令行参数中 * 的问题
Posted
技术标签:
【中文标题】命令行参数中 * 的问题【英文标题】: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 的条目。 【参考方案1】:这是因为*
是一个shell 通配符:它对shell 有特殊含义,它在将其传递给命令之前对其进行扩展(在本例中为java
)。
由于您需要文字 *
,因此您需要将其从 shell 中转义。转义的具体方式因你的 shell 而异,但你可以尝试:
java ProgramName 5 3 "*"
或者:
java ProgramName 5 3 \*
顺便说一句,如果您想知道 shell 对 *
的作用,请尝试将 String[] args
的内容打印到您的 main
方法中。您会发现它将包含您目录中文件的名称。
如果您需要将一些文件名作为命令行参数传递,这会很方便。
另见
Wikipedia: glob
例如,如果一个目录包含两个文件,
a.log
和b.log
,那么命令cat *.log
将被 shell 扩展为cat a.log b.log
Wikipedia: Escape character
在 Bourne shell (
sh
) 中,星号 (*
) 和问号 (?
) 字符是通过通配符扩展的通配符。如果没有前面的转义字符,*
将扩展为工作目录中不以句点开头的所有文件的名称,当且仅当存在此类文件时,否则*
保持未扩展。因此,要引用一个字面上称为"*"
的文件,必须告诉 shell 不要以这种方式解释它,在它前面加上一个反斜杠 (\
)。
【讨论】:
为了完整起见,并且由于 OP 没有提及任何特定的操作系统,请注意,在 Windows 中,通配是应用程序的责任,而不是外壳。它通常由应用程序的运行时库处理。 事实证明,Windows jvm 在某些情况下会在内部执行自己的 globbing,请参阅 ***.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环境中(如你所说)。在这里查看我的笔记:***.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 找到详细信息。
【讨论】:
以上是关于命令行参数中 * 的问题的主要内容,如果未能解决你的问题,请参考以下文章