A Scala shell script example (and discussion)

Scala shell script FAQ: How do I create a Unix/Linux shell script to run a small Scala script?

If you want to run a Scala script as a Unix or Linux shell script — such as hello.sh — write your script like this:

#!/bin/sh
exec scala "$0" "$@"
!#
object HelloWorld {
  def main(args: Array[String]) {
    println("Hello, world! " + args.toList)
  }
}
HelloWorld.main(args)

(This example is taken directly from the Getting Started with Scala web page, but I’ll add a little more to it here.)

If you save this in a file named hello.sh and make the file executable, you can then run it as a shell script like this:

./hello.sh

or with a parameter, like this:

./hello.sh alvin

Scala shell script - discussion

I wasn't comfortable with the second and third lines of the shell script, and they're not explained on that page, so I did a little research.

The exec command is a shell builtin, I did know that much. I found the following details by running man on the sh command and digging through the output:

0  Expands to the name of the shell or shell script.
   This is set at shell initialization. If bash  is  
   invoked  with  a  file  of commands, $0 is set to 
   the name of that file.  If bash is started with 
   the -c option, then $0 is set to the first argument 
   after the string to  be  executed, if one is present.
   Otherwise, it is set to the file name used to invoke 
   bash, as given by argument zero.

@  Expands  to  the  positional  parameters, starting from 
   one. When the expansion occurs within double quotes, each 
   parameter expands to a separate word. That is, "$@" is 
   equivalent to "$1", "$2" ... If the double-quoted 
   expansion occurs within a word, the expansion of the first
   parameter is joined with the beginning part of the original 
   word, and the expansion of the last parameter is joined
   with the last part of the original word. When there are no 
   positional parameters, "$@" and $@ expand to nothing 
   (i.e., they are removed).

I didn't know what the "!#" characters are for, but I learned that if you remove them and try running the shell script, you'll get this error message:

$ ./hello.sh 
error: script file does not close its header with !# or ::!#
one error found

After a little more research ... I've learned that a shell script can have a "header" section, and this is how you close the header section. I've always known about the "#!" syntax, but not this "!#" header closing syntax.

After a little more digging around I've found a reference to using "!#" as a shell script variable on this long page. (Search that page for those characters, and you'll find a couple of references to it.)

If anyone has any more information on this syntax, feel free to leave a comment below.

The Bash exec command

Finally, if you haven't used it before, here's a good link on the exec command. They show that the exec command syntax looks like this:

Syntax
      exec [-cl] [-a name] [command [arguments]]

Options
      -l   Place a dash at the beginning of the zeroth arg passed to command.
           (This is what the login program does.)
      -c   Causes command to be executed with an empty environment.
      -a    The shell passes name as the zeroth argument to command.

and they also offer this description:

If command is supplied, it replaces the shell without creating 
a new process. If no command is specified, redirections may be 
used to affect the current shell environment.

Case classes in Scala scripts

Note also that you can use case classes in Scala scripts, as shown in the following example:

#!/bin/sh
exec scala "$0" "$@"
!#

case class Person(name: String)

object HelloWorld {
  def main(args: Array[String]) {
    val al = Person("Al")
    println(al)
  }
}

HelloWorld.main(args)

That's another feature that can come in handy, as it did in a script I just wrote to email me stock quotes, where I modeled a Stock as a simple case class.

Scala shell script example - Summary

I hope this Scala shell script example, and discussion of the code, has been helpful. As you can see from the code, you can put your Scala code in a shell script and then execute it like a normal shell script, which is what I wanted. Before finding this solution I had my Scala code in one file and then executed it from a separate shell script file, and I didn't like that approach, where this is a cleaner solution that still lets you get at the command line parameters.