Scala shell script FAQ: How do I create a Unix/Linux shell script to run a small Scala script, specifically a Scala 2 shell script?
Solution
If you want to run a Scala 2 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’m going to add a little more to it here.)
If you save this in a file named hello.sh
and make the file executable like this:
chmod +x hello.sh
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.
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |
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.