I\'m working with the Scala scala.sys.process
library.
I know that I can capture the exit code with !
and the output with !!
Here's a really simple Scala wrapper that allows you to retrieve stdout, stderr and exit code.
import scala.sys.process._
case class ProcessInfo(stdout: String, stderr: String, exitCode: Int)
object CommandRunner {
def runCommandAndGetOutput(command: String): ProcessInfo = {
val stdout = new StringBuilder
val stderr = new StringBuilder
val status = command ! ProcessLogger(stdout append _, stderr append _)
ProcessInfo(stdout.toString(), stderr.toString(), status)
}
}
You can use ProcessIO
. I needed something like that in a Specs2 Test, where I had to check the exit value as well as the output of a process depending on the input on stdin
(in
and out
are of type String
):
"the operation" should {
f"return '$out' on input '$in'" in {
var res = ""
val io = new ProcessIO(
stdin => { stdin.write(in.getBytes)
stdin.close() },
stdout => { res = convertStreamToString(stdout)
stdout.close() },
stderr => { stderr.close() })
val proc = f"$operation $file".run(io)
proc.exitValue() must be_==(0)
res must be_==(out)
}
}
I figured that might help you. In the example I am ignoring what ever comes from stderr
.
You can specify an output stream that catches the text:
import sys.process._
val os = new java.io.ByteArrayOutputStream
val code = ("volname" #> os).!
os.close()
val opt = if (code == 0) Some(os.toString("UTF-8")) else None
The one-line-ish use of BasicIO or ProcessLogger is appealing.
scala> val sb = new StringBuffer
sb: StringBuffer =
scala> ("/bin/ls /tmp" run BasicIO(false, sb, None)).exitValue
res0: Int = 0
scala> sb
res1: StringBuffer = ...
or
scala> import collection.mutable.ListBuffer
import collection.mutable.ListBuffer
scala> val b = ListBuffer[String]()
b: scala.collection.mutable.ListBuffer[String] = ListBuffer()
scala> ("/bin/ls /tmp" run ProcessLogger(b append _)).exitValue
res4: Int = 0
scala> b mkString "\n"
res5: String = ...
Depending on what you mean by capture, perhaps you're interested in output unless the exit code is nonzero. In that case, handle the exception.
scala> val re = "Nonzero exit value: (\\d+)".r.unanchored
re: scala.util.matching.UnanchoredRegex = Nonzero exit value: (\d+)
scala> Try ("./bomb.sh" !!) match {
| case Failure(f) => f.getMessage match {
| case re(x) => println(s"Bad exit $x")
| }
| case Success(s) => println(s)
| }
warning: there were 1 feature warning(s); re-run with -feature for details
Bad exit 3
I have the following utility method for running commands:
import sys.process._
def runCommand(cmd: Seq[String]): (Int, String, String) = {
val stdoutStream = new ByteArrayOutputStream
val stderrStream = new ByteArrayOutputStream
val stdoutWriter = new PrintWriter(stdoutStream)
val stderrWriter = new PrintWriter(stderrStream)
val exitValue = cmd.!(ProcessLogger(stdoutWriter.println, stderrWriter.println))
stdoutWriter.close()
stderrWriter.close()
(exitValue, stdoutStream.toString, stderrStream.toString)
}
As you can see, it captures stdout, stderr and result code.
The response provided by 'Alex Cruise' in your link is fairly concise, barring poorer performance.
You could extend sys.process.ProcessLogger to manage the
var out = List[String]()
var err = List[String]()
internally, with getters for the out.reverse and err.reverse results.