如何将 JVM 属性 line.separator 设置为从 bash 换行

how to set JVM property line.separator to newline from bash

我想将 JVM 系统 属性 line.separator 设置为 Windows 上的单个换行符(默认情况下,其他地方已经是单个换行符)。

这个scala脚本用来显示有效line.separator 属性:

#!/usr/bin/env scala
val bytes = sys.props("line.separator").map { _.toInt }.mkString(" ")
printf("line.separator bytes: %s\n",bytes)

在 windows JVM 上,它通常打印以下内容:

line.separator bytes: 13 10

简而言之,我正在寻找一种方法来启动我的测试脚本,以便打印以下输出:

line.separator bytes: 10

我可以通过以下 JAVA_OPTS 设置实现此目的:

export JAVA_OPTS=-Dline.separator=$'\n'

但前提是我还通过用双引号将 $JAVA_OPTS 括起来来修改标准 Scala 脚本。这是接近 scala 脚本末尾的部分(即,没有进行必要的修改):

execCommand \
  "${JAVACMD:=java}" \
  $JAVA_OPTS \
  "${java_args[@]}" \
  "${classpath_args[@]}" \
  -Dscala.home="$SCALA_HOME" \
  $OVERRIDE_USEJAVACP \
  $WINDOWS_OPT \
   scala.tools.nsc.MainGenericRunner  "$@"

通过这两个修改,上面的测试脚本打印如下:

$ reportLineSeparator.sc
line.separator bytes: 10

但是,向 JAVA_OPTS 添加引号不是一个可行的选择,因为这会阻止它被取消设置或指定多个设置。

所以要求似乎是以某种方式安排正确处理未引用的 JAVA_OPTS 而不会丢失编码的换行符。

我开始怀疑是否有解决方案,尽管我希望有人能证明我是错的。

更新:似乎如果使用 bash 数组而不是 JAVA_OPTS,这将提供一个解决方案,因为它可以在 scala 脚本中引用。换句话说,将上面未加引号的 $JAVA_OPTS 替换为:

"${JAVA_OPTS_ARR[@]}" \

令我惊喜的是,当 JAVA_OPTS_ARR 未定义时它也不会引起问题。

但是,这不是一个可行的解决方案,因为无法导出 bash 数组(参见 Exporting an array in bash script

追问:进一步思考这个问题后,我得出结论,插值不是问题所在。需要引号将变量包含为单个命令行参数。因此,这引发了一个问题,即是否可以使用内部字段分隔符 (IFS) 将整个 line.separator 定义保留为不带引号的单个命令行参数。

好吧,看来如果我在 scala 启动脚本中添加以下内容,line.separator 设置似乎会生效:

IFS=' '

然后我可以像这样附加到 JAVA_OPTS 并获得所需的行为:

JAVA_OPTS="$JAVA_OPTS "-Dline.separator=$'\n'

IFS 设置必须先于未加引号的 $JAVA_OPTS 出现。

更新:@som-snytt 建议的这个调用似乎有效:

scala -J-Dline.separator=$'\n' -nc lineSeparatorBytes.sc

JAVA_OPTS 是一个古老的约定,但不是标准。它于 2007 年引入 scala 脚本,并在 2010 年被 -J 取代。

我认为最好的选择(可以这么说)是 scala -J-Dline.separator=$'\r'$'\n'

你的建议现在有一个 PR,这看起来很安全,除了它还保留了案例:

JAVA_OPTS="-Xmx256m <tab> -Xss1m".

Shell 引用太有趣了!我试着每五年左右刷新一次我伤痕累累的记忆。

编辑:答案是将 line.separator 传递给 Scala 的后台编译服务器失败了。编译服务器有几个问题(可以用 fsc 为 "fast" scala 编译器调用),现在已弃用。一如既往,此处的解决方案是使用 -nc 为您的脚本请求 "no compile daemon"。编译脚本需要多花一秒钟,但可以节省数小时或数天的调试时间。