I want to set JVM System property line.separator
to a single newline on Windows (it's already a single newline by default everywhere else).
This scala script is used to display the effective line.separator property:
#!/usr/bin/env scala
val bytes = sys.props("line.separator").map { _.toInt }.mkString(" ")
printf("line.separator bytes: %s\n",bytes)
On a windows JVM, it normally prints the following:
line.separator bytes: 13 10
Briefly, I'm looking for a way to launch my test script so that it prints the following output:
line.separator bytes: 10
I can achive this with the following JAVA_OPTS setting:
export JAVA_OPTS=-Dline.separator=$'\n'
but only if I also modify the standard scala script by surrounding $JAVA_OPTS with double quotes. Here's the section near the end of the scala script verbatim (i.e., WITHOUT the needed modification):
execCommand \
"${JAVACMD:=java}" \
$JAVA_OPTS \
"${java_args[@]}" \
"${classpath_args[@]}" \
-Dscala.home="$SCALA_HOME" \
$OVERRIDE_USEJAVACP \
$WINDOWS_OPT \
scala.tools.nsc.MainGenericRunner "$@"
With these two modifications, the test script above prints the following:
$ reportLineSeparator.sc
line.separator bytes: 10
Adding quotes to JAVA_OPTS is not a viable option, however, since that would prevent it from being unset, or from specifying multiple settings.
So the requirement seems to be to somehow arrange for the unquoted JAVA_OPTS to be correctly handled without losing the encoded newline.
I'm starting to suspect that there is solution, although I'm hopeful that someone will prove me wrong.
Update: it seems that if a bash array is used instead of JAVA_OPTS, that would provide a solution, since it could be quoted in the scala script. In other words, replace the unquoted $JAVA_OPTS above with this:
"${JAVA_OPTS_ARR[@]}" \
I was pleasantly surprised that it also doesn't cause problems when JAVA_OPTS_ARR is undefined.
However, this isn't a viable solution because it's not possible to export bash arrays (see Exporting an array in bash script)
Follow-up: after further thinking about this problem, I concluded that interpolation isn't the issue. The quotes are needed to contain the variable as a single command line argument. So that raises the question as to whether the Internal Field Separator (IFS) could be used to keep the entire line.separator definition as a single command line argument without quotes.
Okay, it seems that if I add the following to the scala launch script, the line.separator setting seems to take effect:
IFS=' '
I can then append to JAVA_OPTS like this and get the desired behavior:
JAVA_OPTS="$JAVA_OPTS "-Dline.separator=$'\n'
The IFS setting has to occur prior to where the unquoted $JAVA_OPTS occurs.
Update: this invocation, suggested by @som-snytt seems to work:
scala -J-Dline.separator=$'\n' -nc lineSeparatorBytes.sc
JAVA_OPTS
is an ancient convention but not a standard. It was introduced to the scala
script in 2007 and overtaken by -J
in 2010.
I think the best option (so to speak) is scala -J-Dline.separator=$'\r'$'\n'
.
There is a PR now for your suggestion, which seems safe, except it also keeps tab for the case:
JAVA_OPTS="-Xmx256m <tab> -Xss1m"
.
Shell quoting is so much fun! I try to refresh my scarred memory every five years or so.
Edit: the answer was that passing the line.separator to Scala's background compile server broke. There are several issues with the compile server (which can be invoked with fsc
for the "fast" scala compiler), which is now deprecated. The solution here, as always, is to use the -nc
to request "no compile daemon" for your script. Compilation of the script takes a second longer, but you save hours or days of debugging.