Подтвердить что ты не робот

Scala Процесс - Зафиксировать стандартный код выхода и выхода

Я работаю с библиотекой Scala scala.sys.process.

Я знаю, что я могу записать код выхода с ! и вывод с !!, но что, если я хочу захватить оба?

Я видел этот ответ qaru.site/info/97089/..., который выглядит многообещающим, но мне интересно, есть ли один лайнер, и я что-то пропустил.

4b9b3361

Ответ 1

Вы можете использовать ProcessIO. Мне нужно было что-то подобное в тесте Specs2 Test, где мне нужно было проверить значение выхода, а также выход процесса в зависимости от ввода на stdin (in и out имеют тип 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)
  }
}

Я подумал, что это может вам помочь. В этом примере я игнорирую то, что происходит из stderr.

Ответ 2

У меня есть следующий способ утилиты для запуска команд:

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)
}

Как вы можете видеть, он захватывает stdout, stderr и result code.

Ответ 3

Вы можете указать выходной поток, который ловит текст:

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

Ответ 4

Однолинейное использование BasicIO или ProcessLogger привлекательно.

scala> val sb = new StringBuffer
sb: StringBuffer = 

scala> ("/bin/ls /tmp" run BasicIO(false, sb, None)).exitValue
res0: Int = 0

scala> sb
res1: StringBuffer = ...

или

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 = ...

В зависимости от того, что вы подразумеваете под захватом, возможно, вас интересует вывод, если код выхода не равен нулю. В этом случае обработайте исключение.

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

Ответ 5

Ответ, предоставленный "Alex Cruise" в вашей ссылке, является довольно кратким, что снижает производительность.

Вы можете расширить sys.process.ProcessLogger для управления

var out = List[String]()
var err = List[String]()

внутри, с геттерами для out.reverse и err.reverse результатов.

Ответ 6

Вот действительно простая оболочка Scala, которая позволяет вам получать stdout, stderr и код выхода.

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)
  }
}