命令行参数中 * 的问题

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.logb.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 找到详细信息。

【讨论】:

以上是关于命令行参数中 * 的问题的主要内容,如果未能解决你的问题,请参考以下文章

什么是命令行参数?本人是c++菜鸟

命令行参数中 * 的问题

python中命令行参数

Python笔记:命令行参数解析

如何在 C++ 程序中使用命令行参数?

scrapy 怎样添加命令行参数