更新:在 cygwin bash shell 中运行基于 JVM 的命令行工具时会出现此问题。虽然我最初认为这与 Scala 有关,但它是 Windows JVM 特有的。这可能是 MSDN 库中重大更改的结果,请参阅下面的评论。
我正在编写一个 scala 实用程序脚本,它采用文字 java 类路径条目并对其进行分析。我希望我的主要方法能够接收带有尾随星号的命令行参数,例如“/*”,但在 cygwin bash session 中运行时似乎无法做到这一点。
这是我的 scala 测试脚本,它显示命令行参数:
# saved to a file called "dumpargs.sc"
args.foreach { printf("[%s]\n",_) }
我希望能够用星号作为参数来调用它,如下所示:
scala -howtorun:script dumpargs.sc "*"
当我在 CMD.EXE shell 中运行它时,它会执行我期望的操作:
c:\cygwin> scala.bat -howtorun:script dumpargs.sc "*"
arg[*]
c:\cygwin>
同样,当在 Linux bash shell 中测试时,唯一的命令行参数由一个星号组成,这也是预期的。
用 C 编写的类似命令行参数转储程序会打印一个裸星号,无论它是从哪个 shell(CMD.EXE 或 bash)运行的。
但是当在 cygwin bash shell 中运行相同的测试时,星号将被通配,列出当前目录中的所有文件。通配符发生在 bash 下游的某个地方,否则 C 转储程序也会失败。
问题很微妙,它发生在 JVM 收到星号参数之后、JVM 调用 main 方法之前的某个地方。但 JVM 仅根据正在运行的 shell 环境中的某些内容来匹配星号。
在某些方面,这种行为是一件好事,因为它通过隐藏运行时环境、Windows 与 Linux/OSX 等之间的差异来支持脚本可移植性(类 UNIX shell 倾向于 glob,而 CMD.EXE 则不然)。
迄今为止解决该问题的所有努力都失败了:
即使我允许依赖于操作系统的技巧,我也尝试了以下所有操作(来自 bash session ):
"*" '*' '\*' '\\*'
以下内容几乎可以工作,但是半引号作为参数值的一部分到达,然后必须被我的程序删除:
"'*'"
同样的问题,但不同类型的不需要的引号通过:
'"*"' or \"*\"
需要的是一个系统属性,或者一些其他机制来禁用通配符。
顺便说一句,这个问题的一个变种是无法利用通过指定“-classpath 'lib/*'”将 jar 文件目录添加到类路径中的好方法(自 java 1.6 起)。
需要有一个系统属性,我可以设置它来在提供自己的通配符的 shell 环境中运行时禁用此行为。
最佳答案
此问题是由 JVM 中的一个已知错误引起的,记录如下:
https://bugs.openjdk.java.net/browse/JDK-8131329
同时,为了解决这个问题,我通过环境变量传递参数。
这是我的“myScalaScript”中发生的事情:
#!/usr/bin/env scala
for( arg <- args.toList ::: cpArgs ){
printf("[%s]\n",arg)
}
lazy val cpArgs = System.getenv("CP_ARGS") match {
case null => Nil
case text => text.split("[;|]+").toList
}
以下是从 bash 调用脚本的方式: CP_ARGS=".|./lib/*"myScalaScript [可能是其他无问题参数]
这是它在所有测试环境中打印的内容:
[.]
[./lib/*]
这里有一个更好的修复方法,它隐藏了脚本中的所有肮脏内容,并且在主循环中更加传统。
新脚本:
#!/bin/bash
export CP_ARGS="$@"
exec $(which scala) "$0"
!#
// vim: ft=scala
for( arg <- cpArgs ){
printf("[%s]\n",arg)
}
lazy val cpArgs = System.getenv("CP_ARGS") match {
case null => Nil
case text => text.split("[;|]+").toList
}
关于java - Windows JVM 命令行参数上的尾随星号在 cygwin bash shell 中被通配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37037375/