Calling an external team as a subprocess in Scala

In Python, if I want to call an external command as a subprocess, I do the following:

from subprocess import Popen, PIPE cmd = ['cat', '-be'] out, err = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate("some input") 

What is the standard way to do the same in Scala? Using Java's ProcessBuilder, I came up with the following, but this is pretty ugly:

 def communicate(cmd: List[String], input: Option[String] = None): (String, String) = { val command = new java.util.ArrayList[String]() cmd.foreach(command.add(_)) val builder = new ProcessBuilder(command) val process = builder.start() val stdinWriter = new java.io.PrintWriter((new java.io.OutputStreamWriter(new java.io.BufferedOutputStream(process.getOutputStream()))), true); val stdoutReader = new java.io.BufferedReader(new java.io.InputStreamReader(process.getInputStream())) val stderrReader = new java.io.BufferedReader(new java.io.InputStreamReader(process.getErrorStream())) input.foreach(stdinWriter.write(_)) stdinWriter.close() def read(reader: java.io.BufferedReader): String = { val out = new ListBuffer[String] var line: String = reader.readLine() while (line != null) { out += line line = reader.readLine() } return out.result.mkString("\n") } val stdout = read(stdoutReader) val stderr = read(stderrReader) stdoutReader.close() stderrReader.close() return (stdout, stderr) } val (catout, caterr) = communicate(List("cat", "-be"), Some("some input")) val (pwdout, pwderr) = communicate(List("pwd")) 

Is there another alternative built into Scala?

+4
source share
3 answers

The answer here is How scala.sys.process works from Scala 2.9? Shows how to use the new Scala 2.9 scala.sys.process.Process. If you are not using 2.9, you can use part of the sbt process; from which the Scala process starts.

+9
source

Have you looked at the Apocal commons exec http://commons.apache.org/exec/tutorial.html ?

I successfully used it from Scala several years ago. Dug out the code:

 def quickRun(command: String, allowedExitCodes: Array[Int]): String = { val executor = new DefaultExecutor() val outputStream = new ByteArrayOutputStream() val errorStream = new ByteArrayOutputStream() val pumpStreamHandler = new PumpStreamHandler(outputStream, errorStream) executor.setStreamHandler(pumpStreamHandler) executor.setExitValues(allowedExitCodes) lazy val errorMsg = "Couldn't execute command: \"" + command + "\", errorStream: " + errorStream.toString() try { val exitValue = executor.execute(CommandLine.parse(command)) if (executor.isFailure(exitValue)) { log.error(errorMsg) throw new CommandLineException(errorMsg) } else { return outputStream.toString() } } catch { case e: ExecuteException => log.error(errorMsg) throw new CommandLineException(errorMsg) case e: IOException => throw new CommandLineException(errorMsg) } } 

But scala.sys.process looks better, I think you should use this if possible ...

0
source

Using the OS-Lib library, your code can be written as the following Scala:

 @ val res = os.proc("cat", "-be").call(stdin = "some input") res: os.CommandResult = CommandResult(0, List(Left( 1 some input))) @ res.out.string res3: String = " 1\tsome input" @ res.err.string res4: String = "" 
0
source

All Articles