考虑以下简单的 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/