如何在没有通配符扩展的情况下将 * 传递给 java 程序?

How to pass * to a java program without wildcard expansion?

考虑以下简单的 Java 程序:

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        System.out.println(Arrays.asList(args));
    }
}

Glob 扩展通常由 shell 完成,而不是由 JVM 完成。例如,在 Cygwin 中:

$ echo *
Main.class

此处Cygwin将*扩展为Main.class(目录中的文件)

可以关闭此行为:

$ set -f
$ echo *
*

现在*还没有展开

然而,当将 * 传递给 Java 程序时,通配符以某种方式被扩展:

$ set -f
$ java Main *
[Main.class]

引用或转义也无济于事:

$ java Main '*'
[Main.class]
$ java Main \*
[Main.class]

谁是这里的罪魁祸首,Shell 或 Java?似乎是 JVM,因为 python 程序运行良好:

Python 文件 a.py:

import sys
print  sys.argv[1:]

运行 python 带通配符的程序:

$ set -f; python a.py *
['*']

没有展开。

JVM为什么要扩展通配符?这应该是 Shell 的函数,而不是 JVM。如何关闭它?

在 Unix 上,全局扩展由 shell 而不是程序处理。

在 Windows 上,glob 扩展由程序处理,而不是由 shell。

这意味着当您 运行 来自 Unix shell 的 Windows 程序时,您可能会经历两次 glob 扩展。

Windows OpenJDK source code 对此负责:

/*
 * At this point we have the arguments to the application, and we need to
 * check with original stdargs in order to compare which of these truly
 * needs expansion. cmdtoargs will specify this if it finds a bare
 * (unquoted) argument containing a glob character(s) ie. * or ?
 */
jobjectArray
CreateApplicationArgs(JNIEnv *env, char **strv, int argc)
{
   // (***snip***)
    NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls,
                                                "expandArgs",
                                                "([Ljava/lang/String;)[Ljava/lang/String;"));

    // expand the arguments that require expansion, the java method will strip
    // out the indicator character.
    NULL_CHECK0(inArray = NewPlatformStringArray(env, nargv, argc));
    outArray = (*env)->CallStaticObjectMethod(env, cls, mid, inArray);

这是它调用的 expandArgs

static String[] expandArgs(List<StdArg> argList) {
    ArrayList<String> out = new ArrayList<>();
      // (***snip***)
            try (DirectoryStream<Path> dstream =
                    Files.newDirectoryStream(parent.toPath(), glob)) {
                int entries = 0;
                for (Path p : dstream) {
                    out.add(p.normalize().toString());
                    entries++;
                }

我不知道是否可以禁用此行为。考虑在文件中传递数据,或使用 Windows 子系统 Linux,它比 CygWin 更准确地模拟 Unix 环境。