windows JVM 命令行参数上的尾随星号在 cygwin 中被通配 bash shell
trailing asterisks on windows JVM command-line args are globbed in cygwin bash shell
更新:当 运行在 cygwin bash shell 中使用基于 JVM 的命令行工具时会出现此问题。虽然我最初认为这与 Scala 有关,但它特定于 Windows JVM。这可能是 MSDN 库中重大更改的结果,请参阅下面的评论。
我正在编写一个 scala 实用程序脚本,它接受文字 java 类路径条目并对其进行分析。我希望我的主要方法能够接收带有尾随星号的命令行参数,例如“/*”,但是当 运行 在 cygwin [=62] 中时似乎没有办法做到这一点=] 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 中是 运行 时,星号是全局的,列出了当前目录中的所有文件。 globbing 发生在 bash 下游的某处,否则 C 转储程序也会失败。
这个问题很微妙,它发生在JVM的某个地方,在它接收到星号参数之后,在JVM调用main方法之前。但是 JVM 只会根据 运行ning shell 环境中的某些东西来匹配星号。
在某些方面,这种行为是一件好事,因为它支持脚本可移植性,通过隐藏 运行 时间环境、Windows 与 Linux/OSX 等的差异( unix-like shells 倾向于 glob,而 CMD.EXE 则不会)。
到目前为止解决该问题的所有努力都失败了:
即使我允许使用 os 依赖的技巧,我也尝试了以下所有方法(来自 bash 会话):
"*" '*' '\*' '\*'
以下 almost 有效,但半引号作为参数值的一部分到达,然后必须被我的程序剥离:
"'*'"
同样的问题,但不同类型的不需要的引号通过了:
'"*"' or \"*\"
我们需要的是一个系统 属性,或其他一些禁用 globbing 的机制。
顺便说一句,这个问题的一个变体是无法利用将 jar 文件目录添加到类路径的好方法(自 java 1.6 起),方法是指定“-classpath” 'lib/*'".
需要一个系统 属性 当 运行 在 shell 提供自己的 globbing 的环境中时,我可以设置禁用此行为。
此问题是由 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) "[=12=]"
!#
// 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
}
更新:当 运行在 cygwin bash shell 中使用基于 JVM 的命令行工具时会出现此问题。虽然我最初认为这与 Scala 有关,但它特定于 Windows JVM。这可能是 MSDN 库中重大更改的结果,请参阅下面的评论。
我正在编写一个 scala 实用程序脚本,它接受文字 java 类路径条目并对其进行分析。我希望我的主要方法能够接收带有尾随星号的命令行参数,例如“/*”,但是当 运行 在 cygwin [=62] 中时似乎没有办法做到这一点=] 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 中是 运行 时,星号是全局的,列出了当前目录中的所有文件。 globbing 发生在 bash 下游的某处,否则 C 转储程序也会失败。
这个问题很微妙,它发生在JVM的某个地方,在它接收到星号参数之后,在JVM调用main方法之前。但是 JVM 只会根据 运行ning shell 环境中的某些东西来匹配星号。
在某些方面,这种行为是一件好事,因为它支持脚本可移植性,通过隐藏 运行 时间环境、Windows 与 Linux/OSX 等的差异( unix-like shells 倾向于 glob,而 CMD.EXE 则不会)。
到目前为止解决该问题的所有努力都失败了:
即使我允许使用 os 依赖的技巧,我也尝试了以下所有方法(来自 bash 会话):
"*" '*' '\*' '\*'
以下 almost 有效,但半引号作为参数值的一部分到达,然后必须被我的程序剥离:
"'*'"
同样的问题,但不同类型的不需要的引号通过了:
'"*"' or \"*\"
我们需要的是一个系统 属性,或其他一些禁用 globbing 的机制。
顺便说一句,这个问题的一个变体是无法利用将 jar 文件目录添加到类路径的好方法(自 java 1.6 起),方法是指定“-classpath” 'lib/*'".
需要一个系统 属性 当 运行 在 shell 提供自己的 globbing 的环境中时,我可以设置禁用此行为。
此问题是由 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) "[=12=]"
!#
// 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
}