Scala: How to handle the STDOUT and STDERR of external commands

This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 12.13, “How to handle the STDOUT and STDERR of external commands.”

Problem

You want to run an external command and get access to both its STDOUT and STDERR in a Scala application.

Solution

The simplest way to do this is to run your commands as shown in previous recipes, and then capture the output with a ProcessLogger. This Scala shell script demonstrates the approach:

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

import sys.process._

val stdout = new StringBuilder
val stderr = new StringBuilder
val status = "ls -al FRED" ! ProcessLogger(stdout append _, stderr append _)

println(status)
println("stdout: " + stdout)
println("stderr: " + stderr)

When this script is run, the status variable contains the exit status of the command. The stdout variable contains the STDOUT if the command is successful (such as with ls -al), and stderr contains the STDERR from the command if there are problems. If the command you’re running writes to both STDOUT and STDERR, both stdout and stderr will contain data.

For instance, assuming you don’t run the following command as root, changing the status expression in the script to the following code should generate output to both STDOUT and STDERR on a Unix system:

val status = Seq("find", "/usr", "-name", "make") ! ProcessLogger(stdout append _, stderr append _)

Running the script with this command on a Mac OS X (Unix) system, I correctly get the following exit status, STDOUT, and STDERR output:

scala> val status = Seq("find", "/usr", "-name", "make") ! ProcessLogger(stdout append _, stderr append _)
status: Int = 1

scala> println(stdout)
/usr/bin/make

scala> println(stderr)
find: /usr/local/mysql-5.0.67-osx10.5-x86/data: Permission denied

Depending on your needs, this can get much more complicated very quickly. The Scaladoc states, “If one desires full control over input and output, then a ProcessIO can be used with run.” See the scala.sys.process API documentation for the ProcessLogger and ProcessIO classes for more examples.

See Also