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

Scala 如何发出产生无限输出并立即返回的命令,scala,ammonite,Scala,Ammonite,当我用ammonite编写以下代码时,但我认为这并不重要 tail-f toTail.txt lineStream foreachprintln_2;,程序按预期给我最后一行,但随后挂起,即使我在文件中写入更多内容,也不会出现任何结果 API如何支持具有无限输出的流程 我尝试编写val myStream=tail-f toTail.txt lineStream_33;! 但它仍然没有回写 以下是scala文档所说的: lineStream:像run一样立即返回,生成的输出通过Stream[Str

当我用ammonite编写以下代码时,但我认为这并不重要

tail-f toTail.txt lineStream foreachprintln_2;,程序按预期给我最后一行,但随后挂起,即使我在文件中写入更多内容,也不会出现任何结果

API如何支持具有无限输出的流程

我尝试编写val myStream=tail-f toTail.txt lineStream_33;! 但它仍然没有回写

以下是scala文档所说的:

lineStream:像run一样立即返回,生成的输出通过Stream[String]提供。获取该流的下一个元素可能会阻塞,直到它可用为止


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

顺便说一下,我和Ammonite API有着完全相同的行为


如果再次键入%%tail,-f,toTail.txt,该方法将挂起,不会立即返回

ProcessBuilder没有问题,至少不是您的用例引起的问题。从:

启动过程

要执行与ProcessBuilder关联的所有外部命令,可以使用四组方法之一。每种方法都有不同的重载和变体,以实现对I/O的进一步控制。这些方法包括:

run:最常用的方法,它立即返回一个scala.sys.process.process,外部命令并发执行。 !: 阻塞,直到所有外部命令退出,并返回执行链中最后一个命令的退出代码。 !!: 块,直到所有外部命令退出,并返回一个包含生成的输出的字符串。 lineStream:像run一样立即返回,生成的输出通过Stream[String]提供。获取该流的下一个元素可能会阻塞,直到它可用为止。如果返回代码不同于零,此方法将引发异常-如果不需要,请使用lineStream!方法 文档中明确指出,lineStream可能会阻塞,直到下一行可用为止。由于tail-f的本质是一个无限的行流lineBreak,程序将阻塞等待下一行出现

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

boom
bar
cat
为什么是lineStream!没有错 产出:

I'm after tail!
boom
bar
cat
Finished
I'm after the tail command...
Such computation performed while tail was active!
Such computation performed while tail was active again!
boom
bar
cat
所以你看到了线流!他立刻回来了。因为命令的性质是有限的

如何从产生无限输出的命令立即返回: 让我们用tail-f试试这个。您需要更多地控制您的流程。同样,正如文件所述:

如果希望完全控制输入和输出,那么scala.sys.process.ProcessIO可以与run一起使用

举个例子:

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 tail!
boom
bar
cat
Finished
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目录回显'fff'>>sample.txt,程序将输出:

Another computation!
Finished
现在,您可以在发出tail-f命令后执行任何您想要的计算,并且可以根据传递给takeWhile方法或关闭输入流的其他方法的条件终止它


有关ProcessIO的更多详细信息,请查看。

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


尝试使用tail-F而不是tail-F,这样应该可以工作。

描述一下您所说的“没有以正确的方式运行”是什么意思我希望返回一个inputStream。但它不返回,它只是在那里停留。可能是我对stream类的工作方式有点困惑。对于要返回的流对象来说,数据应该是有限的而不是无界的?据我所知,流是计算机惰性的。所以这应该不是一个问题,问题可能来自Scala Process Builder方法LineStream,我认为,问题有点不清楚,实际上没有挂起任何东西,也没有任何东西应该立即返回,但问题确实存在。为了澄清:tail-f foo.txt.lineStream.foreachprintln预计不会立即返回,它应该坐在那里,在添加到foo.txt时打印出更多的行。它做的第一件事是坐在那里,但不是另一件事-没有额外的行打印出来,因为它们是在命令启动后添加到文件中的。我想,您回答了一个错误的问题:op的问题似乎是tail-f foo.txt.lineStream.foreachprintln不会打印在命令启动后添加到foo.txt的新行。这确实令人费解…因此我不明白它为什么会阻塞-我回答了它为什么会阻塞。并提供了替代方案。也许当他看到这一点时,他可以澄清:@Dima tail-f foo.txt.lineStream.foreachprintln会打印
被发送到文件:这取决于您将它们发送到文件的方式,也可能取决于您的操作系统。看看我的答案……也许吧。我用echo和>>接线员发送它们。运行El capitan 10.11.6