This is an excerpt from the 1st Edition of the Scala Cookbook (partially modified for the internet). This is Recipe 14.4, “How to run a shell command from the Scala REPL.”
Problem
You want to be able to run a shell command from within the Scala REPL, such as listing the files in the current directory.
Solution
Run the command using the :sh
REPL command, then print the output. The following example shows how to run the Unix ls -al
command from within the REPL, and then show the results of the command:
scala> :sh ls -al res0: scala.tools.nsc.interpreter.ProcessResult = `ls -al` (6 lines, exit 0) scala> res0.show total 24 drwxr-xr-x 5 Al staff 170 Jul 14 17:14 . drwxr-xr-x 29 Al staff 986 Jul 14 15:27 .. -rw-r--r-- 1 Al staff 108 Jul 14 15:34 finance.csv -rw-r--r-- 1 Al staff 469 Jul 14 15:38 process.scala -rw-r--r-- 1 Al staff 412 Jul 14 16:24 process2.scala
Alternatively you can import the scala.sys.process package, and then use the normal Process
and ProcessBuilder
commands described in Recipe 12.11, “Executing External Commands”:
scala> import sys.process._ import sys.process._ scala> "ls -al" ! total 24 drwxr-xr-x 5 Al staff 170 Jul 14 17:14 . drwxr-xr-x 29 Al staff 986 Jul 14 15:27 .. -rw-r--r-- 1 Al staff 108 Jul 14 15:34 finance.csv -rw-r--r-- 1 Al staff 469 Jul 14 15:38 process.scala -rw-r--r-- 1 Al staff 412 Jul 14 16:24 process2.scala res0: Int = 0
Scala’s -i option
Although those examples show the correct approach, you can improve the situation by loading your own custom code when you start the Scala interpreter. For instance, I almost always start the REPL in my /Users/Al/tmp directory, and I have a file in that directory named repl-commands with these contents:
import sys.process._ def clear = "clear".! def cmd(cmd: String) = cmd.!! def ls(dir: String) { println(cmd(s"ls -al $dir")) } def help { println("\n=== MY CONFIG ===") "cat /Users/Al/tmp/repl-commands".! } case class Person(name: String) val nums = List(1, 2, 3) val strings = List("sundance", "rocky", "indigo") // lets me easily see the methods from StringOps // with tab completion val so = new collection.immutable.StringOps("")
With this setup, I start the Scala interpreter with the -i
argument, telling it to load this file when it starts:
$ scala -i repl-commands
This makes those pieces of code available to me inside the REPL. For instance, I can clear my terminal window by invoking the clear
method:
scala> clear
My ls
method provides a directory listing:
scala> ls("/tmp")
With my cmd
method I can run other external commands:
scala> cmd("cat /etc/passwd")
The help
method uses the system cat
command to display this file, which is helpful if I haven’t used it in a while. The nums
and strings
variables and Person
class also make it easy to run quick experiments.
This approach is similar to using a startup file to initialize a Unix login session, like a .bash_profile file for Bash users, and I highly recommend it. As you use the REPL more and more, use this technique to customize its behavior.
To make this even easier, I created the following Unix alias and put it in my .bash_profile file:
alias repl="scala -i /Users/Al/tmp/repl-commands"
I now use this alias to start a REPL session, rather than starting it by typing scala
:
$ repl
See Also
- The “Executing external commands” recipes in Chapter 12 for more examples of executing external commands from Scala code
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |