Scala Process - Capture Standard Out and Exit Code

后端 未结 6 2242
心在旅途
心在旅途 2020-12-13 06:21

I\'m working with the Scala scala.sys.process library.

I know that I can capture the exit code with ! and the output with !!

相关标签:
6条回答
  • 2020-12-13 06:54

    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)
      }
    }
    
    0 讨论(0)
  • 2020-12-13 06:58

    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.

    0 讨论(0)
  • 2020-12-13 06:59

    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
    
    0 讨论(0)
  • 2020-12-13 07:00

    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
    
    0 讨论(0)
  • 2020-12-13 07:01

    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.

    0 讨论(0)
  • 2020-12-13 07:03

    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.

    0 讨论(0)
提交回复
热议问题