0

Programming Scala says:

Invoking scripts with scala is tedious when you use these scripts frequently. On Windows and Unix-like systems, you can create standalone Scala scripts that don’t require you to use the scala script-file-name invocation. For Unix-like systems, the following example demonstrates how to make an executable script. Remember that you have to make the permissions executable, e.g., chmod +x secho:

#!/bin/sh
# src/main/scala/progscala2/toolslibs/secho
exec scala "$0" "$@"
!#
print("You entered: ")
args.toList foreach { s => printf("%s ", s) }
println

Here is how you might use it:

$ secho Hello World
You entered: Hello World

I was wondering what it means by

# src/main/scala/progscala2/toolslibs/secho
exec scala "$0" "$@"
!#

in sh?

Can I make a Scala script standalone as

#!/path/to/scala
print("You entered: ")
args.toList foreach { s => printf("%s ", s) }
println

on Linux?

Thanks!

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
Tim
  • 101,790

1 Answers1

4

In sh,

# src/main/scala/progscala2/toolslibs/secho

is a comment, ignored;

exec scala "$0" "$@"

causes the current process to replace itself with scala, and all the shell parameters as arguments;

!#

has no effect because the shell has stopped reading the script at this point.

However Scala handles script files by ignoring a “header” at the start of the file; that header starts at a line beginning with #! (or ::#! on Windows) and ends with a line matching either !# (::!#) or /env. The header can be a single line, so both

#!/path/to/scala
!#
print("You entered: ")
args.toList foreach { s => printf("%s ", s) }
println

and

#!/usr/bin/env scala
print("You entered: ")
args.toList foreach { s => printf("%s ", s) }
println

work (the latter requires scala to be on the PATH). The latter corresponds to the documentation.

(!# is the symmetric of #!, and is used in Scala to close the “header” opened by #!, in a fashion similar to /* and */ for comments in C.)

Stephen Kitt
  • 434,908
  • Thanks. What does !# mean? – Tim Mar 18 '20 at 11:30
  • 1
    See the update. – Stephen Kitt Mar 18 '20 at 12:30
  • (1) I just happened to see that some said !# is a shell feature not related to Scala http://alvinalexander.com/scala/scala-shell-script-example-exec-syntax. (2) ${!#} means final positional parameter http://tldp.org/LDP/abs/html/abs-guide.html, but here it is !#, not sure if these two are related. (3) As youre reply says, there seems to be two ways writing a Scala script. Are both equivalent? when to use which, if you happen to know. – Tim Mar 18 '20 at 13:50
  • (1) The author of that post is learning as he writes, “I didn't know what the "!#" characters are for” etc. The error message he mentions is output by scala, not by the shell. (2) No, they are not related. The shell isn’t involved at all in handling !#, it stops running before it gets to that line. (3) Given that the latter form works now, and is simpler, you might as well use that. Presumably older versions of Scala don’t support it, which is why the first form exists; but instead of looking at old docs, look at the current Scala docs, which refer to the simpler form. – Stephen Kitt Mar 18 '20 at 13:54
  • Thanks. I found https://unix.stackexchange.com/questions/365436/choose-interpreter-after-script-start-e-g-if-else-inside-hashbang/365447#comment648996_365447. I also don't find !# in scala language specification https://www.scala-lang.org/docu/files/doc/scala-documentation/ScalaReference.pdf – Tim Mar 18 '20 at 14:54
  • Is the complication specific to Scala or common to other languages? – Tim Mar 18 '20 at 17:55
  • It applies to any language where you want to support a shebang but “#” doesn’t introduce comments. – Stephen Kitt Mar 18 '20 at 18:52
  • (1) Do you mean Scala compiler/interpreter does not treat #!/path/to/scala as a comment? Why does #!/usr/bin/env scala work then? (2) Is !# used specifically for Scala or not specific to any language? (I don't find it in Scala language specification, and suspect it is not specific to any language.) – Tim Mar 18 '20 at 19:28
  • (1) See the update, /usr/bin/env (or rather, /env) is handled specifically. (2) !# is specific to Scala, although since it’s the symmetric of !# it’s possible other languages use a similar approach. – Stephen Kitt Mar 19 '20 at 08:18