如何发出产生无限输出并立即返回的命令



当我编写以下代码时(在ammonite中,但我认为这不重要)

("tail -f toTail.txt" lineStream) foreach(println(_)),该程序给了我最后一行,但随后挂起,即使我在文件中写了更多,也没有出来。

API支持过程如何无界输出?

我尝试写val myStream = ("tail -f toTail.txt" lineStream_!)但是它仍然不会返回书写

这是Scala Doc所说的:

linestream:立即返回像运行一样返回,并且通过流[String]提供了要生成的输出。获取该流的下一个元素可能会阻塞直到可用为止。

因此,我不明白为什么它会阻止

顺便说一句,我的行为与ammonite api

完全相同

如果再次类型%%("tail", "-f", "toTail.txt"),该方法只会悬挂而不会立即返回。

ProcessBuilder没有问题(至少不是您的用例造成的)。从ProcessBuilder文档中:

开始过程

要执行与ProcessBuilder关联的所有外部命令,可以使用四组方法之一。这些方法中的每一种都有各种过载和变化,以进一步控制I/O。这些方法是:

  • 运行:最通用的方法,它立即返回scala.sys.process.process,外部命令同时执行。
  • !:阻止所有外部命令退出,并返回执行链中最后一个的退出代码。
  • !!:阻止所有外部命令退出,并返回带有产生的输出的字符串。
  • lineStream:立即返回像运行一样返回,并且通过流[String]提供了要生成的输出。获取该流的下一个元素可能会阻塞,直到它可用为止。如果返回代码不同于零,则此方法将引发异常 - 如果不需要,请使用Linestream_!方法。

文档清楚地指出,lineStream可能会阻塞,直到下一行可用为止。由于tail -f的性质是无限线lineBreak,该程序将阻止等待下一行出现。

以下假设我有一个文件: /Users/user/tmp/sample.txt,其中内容为:

boom
bar
cat

为什么lineStream_!没有错

import scala.language.postfixOps
import scala.sys.process._
object ProcessBuilder extends App {
  val myStream: Stream[String] = ("tail /Users/user/tmp/sample.txt" lineStream_!)
  println("I'm after tail!")
  myStream.filter(_ != null).foreach(println)
  println("Finished")
  System.exit(0)
}

输出:

I'm after tail!
boom
bar
cat
Finished

因此,您会看到lineStream_!立即返回。因为命令的性质是有限的。

如何立即从产生无限输出的命令中返回:

让我们使用tail -f尝试一下。您需要对过程的更多控制。同样,正如文档所述:

如果一个人希望完全控制输入和输出,则可以与Run一起使用Scala.sys.process.processio。

因此:

import java.io.{BufferedReader, InputStreamReader}
import scala.language.postfixOps
import scala.sys.process._
object ProcessBuilder extends App {
  var reader: BufferedReader = _
  try {
    var myStream: Stream[String] = Stream.empty
    val processIO = new ProcessIO(
      (os: java.io.OutputStream) => ??? /* Send things to the process here */,
      (in: java.io.InputStream) => {
        reader = new BufferedReader(new InputStreamReader(in))
        myStream = Stream.continually(reader.readLine()).takeWhile(_ != "ff")
      },
      (in: java.io.InputStream) => ???,
      true
    )
    "tail -f /Users/user/tmp/sample.txt".run(processIO)
    println("I'm after the tail command...")
    Thread.sleep(2000)
    println("Such computation performed while tail was active!")
    Thread.sleep(2000)
    println("Such computation performed while tail was active again!")
    println(
      s"Captured these lines while computing: ${myStream.print(System.lineSeparator())}")
    Thread.sleep(2000)
    println("Another computation!")
  } finally {
    Option(reader).foreach(_.close())
  }
  println("Finished")
  System.exit(0)
}

输出:

I'm after the tail command...
Such computation performed while tail was active!
Such computation performed while tail was active again!
boom
bar
cat

它仍然立即返回,现在它挂在那里等待更多输入。如果我从tmp目录进行echo 'fff' >> sample.txt,则程序输出:

Another computation!
Finished

您现在有能力执行您想要的任何计算,并在发出tail -f命令和终止它的功能后,取决于您传递给takeWhile方法的条件(或其他关闭输入流的方法)。

有关ProcessIO的更多详细信息,请在此处检查文档。

我认为,这与您将数据添加到文件中,而不是与ProcessBuilder有关。例如,如果您在编辑器中使用它来添加数据,则每次保存时,它都会以不同的inode重写整个文件,而tail则无法检测到。

尝试做tail -F而不是tail -f,应该有效。

最新更新