I have been using shebang #!
for a while and today came across a use case that confuses me.
There are several ways to run scala script like
#!/usr/bin/env scala
println("hello world")
However, I came across this version of shebang
#!/bin/sh
exec scala "$0" "$@"
!#
println("hello world")
Looks like this solution basically invokes the bash first, the run exec scala "$0" "$@"
where $0
denotes the current file name and $@
is input arguments in a positional array.
My question is does that mean everything between #!
and !#
could be executed in bash,
#!/bin/sh
exec scala "$0" "$@"
echo "oh Yeah"
!#
println("hello world")
It did not error out but neither gave me the "oh Yeah" in the stdout, can anyone explain to me what is going on here?
update: after realizing !#
is a scala thing, I downloaded the source code of scala and realized it only appears in the comment of ScriptRunner.scala part written by Lex Spoon.
The informal phrase"the whole shebang" means "everything," which you could also call "the whole ball of wax" or "the whole enchilada." Shebang is an American word, first used by Civil War soldiers (and the poet Walt Whitman) to mean "rustic dwelling" or "hut." In 1872, Mark Twain used shebang to mean "vehicle," but ...
Etymology 1 In the sense of “temporary shelter”, it was perhaps brought by US Civil War Confederate enlistees from Louisiana, from French chabane (“hut, cabin”), a dialectal form of French cabane (“a covered hut, lodge, cabin”) (see cabin, cabana).
The most common need for using shebang appears when we're writing shell scripts. “/bin/sh” is actually the symlink to an sh-compatible implementation of sh (Shell Command Language). In most cases, it'll be bash (Bourne-Again SHell), but if we want to secure portability, we should use the symlink.
The !#
line has no meaning to the shell.
The #!/bin/sh
line means that the script is executed by /bin/sh
. The exec scala "$0" "$@"
line invokes scala
, passing the name of the script and its arguments to the scala
command. Since exec
doesn't return, the shell doesn't see the rest of the script.
I don't know Scala, but my educated guess is that the Scala interpreter itself treats everything from the #!
line to the !#
line as a comment. It then starts executing with the Scala statement println("hello world")
.
In short the !#
is Scala syntax, not shell syntax (but the Scala syntax is designed to let it be used like this in a shell script).
In a quick look at the Scala Language Specification, I haven't found out how this is defined. It's mentioned, but not explained, in this question. It's likely, as chepner 3's comment suggests, that it's a hack in the Scala interpreter rather than part of the actual language syntax.
som-snytt found the code in the Scala interpreter that implements this here:
object ScriptSourceFile {
/** Length of the script header from the given content, if there is one.
* The header begins with "#!" or "::#!" and ends with a line starting
* with "!#" or "::!#".
*/
...
But I wonder whether it's documented.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With