java - 如何在不使用通配符扩展的情况下将 * 传递给 java 程序?

标签 java bash cygwin glob

考虑以下简单的 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 上,glob 扩展由 shell 处理,而不是由程序处理。

在 Windows 上,全局扩展由程序处理,而不是由 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 Subsystem for Linux,它比 CygWin 更准确地模拟 Unix 环境。

关于java - 如何在不使用通配符扩展的情况下将 * 传递给 java 程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48949668/

相关文章:

c# - 从 .NET 执行 Cygwin 进程?

java - JNI->MonitorEnter 的替代方案

Java 8 stream partitioningBy 假条件下的第二个谓词

java - 从带有 Maven 的 Visual Studio Code for Java 开始

linux - 为什么从用作监视服务的 bash 脚本启动的进程在脚本终止后仍然存在?

linux - Bash 别名在文件名中创建具有当前时间戳的文件

linux - 使用 cygwin 添加 FILE_SHARE_READ 模式

java - 为什么使用 Spark 和斯坦福 NLP 运行 java 代码时会发生此异常?

bash - 在 Bash 函数中更改全局位置参数

terminal - 如何解决 “A required library with BLAS API not found”问题?