shebang.md

December 6, 2023 ยท View on GitHub

import {ChainedSnippets} from "../../../src/components/MarkdownComponents.js";

This guide explains the differences between the run and shebang sub-commands, mainly covering how each of them parses its arguments.

shebang script headers

Before proceeding, let's discuss how Scala CLI works in a script without the shebang command. Here is a simple hello.sc script with a shebang header:

#!/usr/bin/env -S scala-cli -S 3

println(args.size)
println(args.headOption)

And it works correctly:

chmod +x hello.sc
./hello.sc    
0
None

And it also works:

./hello.sc -- Hello World
2
Some(Hello)

Note that the extra -- must be added to make it work. If it is not supplied, the result is:

./hello.sc Hello World
[error] Hello: input file not found
World: input file not found

If we modify our script slightly and use the shebang sub-command in the header, we will get the following:

#!/usr/bin/env -S scala-cli shebang -S 3

println(args.size)
println(args.headOption)
./hello.sc Hello World
2
Some(Hello)

shebang and the command line

Let's now see how the shebang command works straight from the command line.

object Main {
  def main(args: Array[String]): Unit = println(args.mkString(" "))
}  
scala-cli shebang Main.scala Hello world
Hello world

:::note Please note that shebang changing how arguments are parsed means that every option after the first input will be treated as an argument to the app.

scala-cli shebang Main.scala -S 2.13 #-S 2.13 is not recognised as an option, but as app arguments
-S 2.13
:::

If we try to do the same with the run sub-command, we get the following error:

scala-cli run Main.scala Hello world
[error]  Hello: input file not found
world: input file not found

Script files' extensions

When running the shebang subcommand, script files don't need the .sc extension, but they are then REQUIRED to start with a shebang line:

#!/usr/bin/env -S scala-cli shebang -S 3

println(args.size)
println(args.headOption)
chmod +x hello-with-shebang
./hello-with-shebang Hello World
2
Some(Hello)
println(args.size)
println(args.headOption)
chmod +x hello-no-shebang
scala-cli shebang hello-no-shebang Hello World
hello-no-shebang: unrecognized source type (expected .scala or .sc extension, or a directory)

:::note Files with no extensions are always run as scripts even though they may contain e.g. valid .scala program. :::