考虑遵循简单的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]
谁是罪魁祸首,壳牌还是Java?它似乎是JVM,因为python程序运行正常:
Python文件a.py
:
import sys
print sys.argv[1:]
使用通配符运行python程序:
$ set -f; python a.py *
['*']
没有扩张。
为什么JVM扩展通配符?这应该是Shell的功能,而不是JVM。如何关闭它?
答案 0 :(得分:1)
在Unix上,glob扩展由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环境。