scala 在cygwin bash shell中,windows JVM命令行参数上的尾随字符串被globbed

yshpjwxd  于 2023-10-18  发布在  Scala
关注(0)|答案(1)|浏览(155)

更新:在cygwin bash shell中运行基于JVM的命令行工具时会出现此问题。虽然我最初认为这与Scala有关,但它是特定于Windows JVM的。这可能是由于破坏了MSDN库中的更改,请参阅下面的注解。
我正在写一个scala实用程序脚本,它接受一个java类路径条目并分析它。我希望我的main方法能够接收带有星号的命令行参数,例如“/*",但是在cygwin bash会话中运行时似乎没有办法做到这一点。
下面是我的scala测试脚本,它显示命令行参数:

  1. # saved to a file called "dumpargs.sc"
  2. args.foreach { printf("[%s]\n",_) }

我希望能够用星号作为参数调用它,像这样:

  1. scala -howtorun:script dumpargs.sc "*"

当我在CMD.EXE shell中运行它时,它会按照我的预期运行:

  1. c:\cygwin> scala.bat -howtorun:script dumpargs.sc "*"
  2. arg[*]
  3. c:\cygwin>

同样,在Linux bash shell中测试时,唯一的命令行参数由一个空星号组成,这也是预期的。
一个用C编写的类似的命令行args dumper程序会打印一个单独的星号,而不管它是从哪个shell(CMD.EXE还是bash)运行。
但是,当在cygwin bash shell中运行相同的测试时,星号是globbed,列出当前目录中的所有文件。globbing发生在bash下游的某个地方,因为否则,C转储程序也会失败。
这个问题很微妙,它发生在JVM中的某个地方,在JVM收到星号参数之后,在JVM调用main方法之前。但是JVM只是基于运行的shell环境中的某些东西来显示星号。
在某些方面,这种行为是一件好事,因为它通过隐藏运行时环境、Windows与Linux/OSX等的差异来支持脚本可移植性(类Unix shell倾向于glob,而CMD.EXE则不会)。
到目前为止,解决这个问题的所有努力都失败了:
即使我允许依赖于操作系统的技巧,我也尝试了以下所有方法(来自bash会话):

  1. "*" '*' '\*' '\\*'

下面的代码几乎可以工作,但是半引号作为参数值的一部分到达,然后必须由我的程序剥离:

  1. "'*'"

同样的问题,但不同类型的不必要的报价得到通过:

  1. '"*"' or \"*\"

我们需要的是一个系统属性,或者其他一些机制来禁用globbing。
顺便说一下,这个问题的一个变体是无法利用将jar文件目录添加到类路径的好方法(从java 1.6开始),即指定“-classpath 'lib/lib'”。
需要有一个系统属性,我可以设置为禁用这种行为时,运行在一个shell环境,提供自己的globbing。

omhiaaxx

omhiaaxx1#

这个问题是由JVM中的一个已知bug引起的,记录在这里:
https://bugs.openjdk.java.net/browse/JDK-8131329
同时,为了解决这个问题,我通过一个环境变量传递参数。
下面是我的“myScalaScript”中发生的事情:

  1. #!/usr/bin/env scala
  2. for( arg <- args.toList ::: cpArgs ){
  3. printf("[%s]\n",arg)
  4. }
  5. lazy val cpArgs = System.getenv("CP_ARGS") match {
  6. case null => Nil
  7. case text => text.split("[;|]+").toList
  8. }

下面是如何从bash调用脚本:CP_ARGS="。|./lib/*”myScalaScript [possibly-other-non-problematic-args]
这是它在所有测试环境下的打印结果:

  1. [.]
  2. [./lib/*]

这里有一个更好的解决方案,它隐藏了脚本中的所有恶意内容,并且在主循环中更常规一些。
新剧本:

  1. #!/bin/bash
  2. export CP_ARGS="$@"
  3. exec $(which scala) "$@"
  4. !#
  5. // vim: ft=scala
  6. for( arg <- cpArgs ){
  7. printf("[%s]\n",arg)
  8. }
  9. lazy val cpArgs = System.getenv("CP_ARGS") match {
  10. case null => Nil
  11. case text => text.split("[;|]+").toList
  12. }
展开查看全部

相关问题