【问题标题】:How to pass * to a java program without wildcard expansion?如何在没有通配符扩展的情况下将 * 传递给 java 程序?
【发布时间】:2018-08-03 14:48:35
【问题描述】:

考虑以下简单的 Java 程序:

import java.util.Arrays;

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

全局扩展通常由 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。如何关闭它?

【问题讨论】:

  • 不清楚你在问什么:你真正想要哪些行为?或者,如果不在上面,你想让它做什么?
  • 这里有什么问题?或者你只是在一些关于它的文件之后? *.java.net上关于它的文章很少
  • @Andy 更改了标题以更好地反映意图。 JVM 应该保持原样。事实上,这里有很多关于 SO 的问题,询问如何让 JVM 扩展 glob。答案是不能。这是 shell 的一个特性,而不是 JVM。
  • Wouldn't escape work??如:java Main *
  • @oldercoder 转义?你是说java Main \*?不,它没有

标签: java bash cygwin glob


【解决方案1】:

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

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

这意味着当您从 Unix shell 运行 Windows 程序时,您可能会面临两次全局扩展的风险。

这是负责此操作的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 子系统 for Linux,它比 CygWin 更准确地模拟 Unix 环境。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-14
    • 1970-01-01
    • 2014-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-25
    • 1970-01-01
    相关资源
    最近更新 更多