Scala: How to execute (exec) external system commands

Scala exec FAQ: How do I execute external system commands in Scala?

When it comes to executing external system commands, Scala is a dramatic improvement over Java. The operators Scala makes available are much more like Perl or Ruby, and the operators themselves are consistent with traditional shell commands, and are therefore easy to remember. Let's take a look at a few examples.

Executing system commands and getting their status code (exit code)

It's very easy to run external system commands in Scala. You just need one import statement, and then you run your command as shown below with the "!" operator:

scala> import sys.process._
import sys.process._

scala> "ls -al" !
total 64
drwxr-xr-x  10 Al  staff   340 May 18 18:00 .
drwxr-xr-x   3 Al  staff   102 Apr  4 17:58 ..
-rw-r--r--   1 Al  staff   118 May 17 08:34 Foo.sh
-rw-r--r--   1 Al  staff  2727 May 17 08:34 Foo.sh.jar
res0: Int = 0

(If you're not familiar with the Unix "ls -al" command, it shows a list of files and directories in the current directory.)

If you're familiar with Scala and the REPL environment, you can see that this command returns a result of zero (0). We can demonstrate that by assigning this command to a variable, and then printing that variable.

scala> val result = "ls -al" !
total 64
drwxr-xr-x  10 Al  staff   340 May 18 18:00 .
drwxr-xr-x   3 Al  staff   102 Apr  4 17:58 ..
-rw-r--r--   1 Al  staff   118 May 17 08:34 Foo.sh
-rw-r--r--   1 Al  staff  2727 May 17 08:34 Foo.sh.jar
result: Int = 0

scala> println(result)
0

If you're familiar with programming Unix shell scripts, you know that a return code of zero is good (it means "success"), while any other value means there was a problem.

Getting output from system commands

While it's often nice to be able to execute system commands and get access to the status code of the command, you'll often want to be able to execute a command and get the output from that command. In Scala you do that with the "!!" operator:

scala> val result = "ls -al" !!
result: String = 
"total 64
drwxr-xr-x  10 Al  staff   340 May 18 18:00 .
drwxr-xr-x   3 Al  staff   102 Apr  4 17:58 ..
-rw-r--r--   1 Al  staff   118 May 17 08:34 Foo.sh
-rw-r--r--   1 Al  staff  2727 May 17 08:34 Foo.sh.jar
"

scala> println(result)
total 64
drwxr-xr-x  10 Al  staff   340 May 18 18:00 .
drwxr-xr-x   3 Al  staff   102 Apr  4 17:58 ..
-rw-r--r--   1 Al  staff   118 May 17 08:34 Foo.sh
-rw-r--r--   1 Al  staff  2727 May 17 08:34 Foo.sh.jar

As you can see in this example, result is now a normal Scala String, and you can operate on it as desired.

Running system commands in a pipeline

When you want to run external system commands in a pipeline, your first instinct will be to try to run them like this:

val result = "ls -al | grep Foo" !

However, as you'll see in the REPL, this won't work:

scala> val result = "ls -al | grep Foo" !
ls: Foo: No such file or directory
ls: grep: No such file or directory
ls: |: No such file or directory
result: Int = 1

I discussed why this doesn't work when you use the Java Process and ProcessBuilder classes many years ago, but in short, the problem is that you're trying to execute a pipeline, and a pipe is a shell construct, and you don't have a shell. That is, your command isn't really being run in an "sh", Bash, csh, or Korn shell; it's just being run from a Scala environment, and Scala doesn't offer a pipeline construct ... well, not like that anyway.

There are several ways to get around this pipeline problem, and the easiest one is to use the Scala pipeline approach, like this:

scala> val result = "ls -al" #| "grep Foo" !
-rw-r--r--   1 Al  staff   118 May 17 08:34 Foo.sh
-rw-r--r--   1 Al  staff  2727 May 17 08:34 Foo.sh.jar
result: Int = 0

As you can see, Scala has a "#|" operator that works just like the "|" pipeline operator of a shell environment, so you can string commands together. If I was working on a system that was running Apache processes, I could get the number of running Apache processes like this:

val result = "ps auxw" #| "grep http" #| "wc -l" !

Scala operators mimic normal shell operators

A great thing about Scala in this regard is that not only does Scala offer a pipeline operator, it also offers other traditional shell operators. You just have to precede them with the "#" character, like this:

#<   Redirect STDIN

#>   Redirect STDOUT
#>>  Append to STDOUT

#&&  Create an AND list
#!!  Create an OR list

I'll demonstrate these more in future Scala tutorials, or extend this tutorial, but I'm out of time for today, so I hope this has been helpful as is.

More information on executing system commands in Scala

For more information on executing system commands in Scala, I encourage you to check out the Scala API docs. They show several more complicated examples, including how to execute pipeline commands using the ProcessBuilder class:

Until I get a chance to write a few more "Scala exec" tutorials, I hope that documentation will be very helpful.