使用Scala的sys.process来解决

时间:2016-08-27 00:30:13

标签: scala

我需要从我的Scala代码执行外部二进制文件并获取其输出。执行此操作的标准方法似乎是使用scala.sys.process。以下代码主要有效:

import scala.sys.process._
val command = Seq("python3", "-c", "print('foo', end='')")
val result = command.!!

但是,似乎还有一个额外的尾随换行符:

print(result.length) // prints 4 instead of 3
print(result) // prints an extra newline at the end

我可以修改结果字符串以删除最后一个字符,但是sys.process会为输出添加一个尾随换行符似乎很奇怪,所以我认为它可能是我正在做的事情的错误或者是可以配置。

尾随的换行符应该在那里吗?

有没有办法在不操纵输出字符串的情况下摆脱它?

3 个答案:

答案 0 :(得分:3)

你试过val result = cmd.lineStream吗? (或相关的.lineStream_!,它可以提供一些异常保护。)

结果是Stream[String]。流的每个元素都是来自进程的输出字符串,其中保留了空格,但没有换行符,因为它是流元素分隔符。

添加的换行符似乎是针对使用!!启动的流程而设计的。

ProcessBuilderImpl.scala中:

def !! = slurp(None, withIn = false)

...

private[this] def slurp(log: Option[ProcessLogger], withIn: Boolean): String = {
  val buffer = new StringBuffer
  val code   = this ! BasicIO(withIn, buffer, log)

  if (code == 0) buffer.toString
  else scala.sys.error("Nonzero exit value: " + code)
}

BasicIO.scala中:

def apply(withIn: Boolean, buffer: StringBuffer, log: Option[ProcessLogger]) =
    new ProcessIO(input(withIn), processFully(buffer), getErr(log))

...

def processFully(buffer: Appendable): InputStream => Unit =
  processFully(appendLine(buffer))

...

private[this] def appendLine(buffer: Appendable): String => Unit = line => {
    buffer append line
    buffer append Newline  <--!!
}

答案 1 :(得分:2)

sys.process 不是添加尾随换行符:echo是。来自documentation

  

说明        echo实用程序写入任何指定的操作数,用单个空格分隔(') characters and followed by a newline ( \ n&#39;)   字符,标准输出。

使用trim可以删除此内容。否则,如果你的shell支持它,你可以这样做:

val result = "echo -n foo".!!

答案 2 :(得分:1)

为了保留所显示的输出,您必须在进行任何NewLine解释(或添加)之前截取InputStream

import sys.process._

val cmnd = Seq("/bin/echo","-n","one\n\nthree")

val stdOutBuf = new StringBuilder
val pio = new ProcessIO(_.close()  //ignore STDIN
  ,out=>{                          //save STDOUT
    val src = io.Source.fromInputStream(out)
    src.foreach(stdOutBuf.+=)
    src.close()
  },_.close())                     //ignore STDERR (or not, up to you)

val exitCode :Int = cmnd.run(pio).exitValue()
val exactOutput :String = stdOutBuf.result()