如何发出立即产生无限输出和 return 的命令
How to issue a command that produces infinite output and return immediately
当我编写以下代码时(在菊石中但我认为这不重要)
("tail -f toTail.txt" lineStream) foreach(println(_))
,程序按照预期给我最后一行但随后挂起,即使我在文件中写了更多内容,也没有任何结果。
API 如何支持具有无限输出的进程?
我试着写val myStream = ("tail -f toTail.txt" lineStream_!)
但它仍然没有return写掉
这是 scala 文档所说的内容:
lineStream: returns immediately like run, and the output being generated is provided through a Stream[String]. Getting the next element of that Stream may block until it becomes available.
所以我不明白为什么它会阻塞
顺便说一句,我和 Ammonite 的行为完全一样 API
如果再次输入 %%("tail", "-f", "toTail.txt")
该方法只是挂起,不会立即 return。
ProcessBuilder 没有问题(至少不是源于您的用例的问题)。来自 ProcessBuilder documentation:
Starting Processes
To execute all external commands associated with a ProcessBuilder, one may use one of four groups of methods. Each of these methods have various overloads and variations to enable further control over the I/O. These methods are:
- run: the most general method, it returns a scala.sys.process.Process immediately, and the external command executes concurrently.
- !: blocks until all external commands exit, and returns the exit code of the last one in the chain of execution.
- !!: blocks until all external commands exit, and returns a String with the output generated.
- lineStream: returns immediately like run, and the output being generated is provided through a Stream[String]. Getting the next element of that Stream may block until it becomes available. This method will throw an exception if the return code is different than zero -- if this is not desired, use the lineStream_! method.
文档明确指出 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_!
return 立即编辑了。因为命令的性质是有限的。
如何从产生无限输出的命令中立即return:
让我们用 tail -f
试试这个。您需要对流程进行更多控制。同样,正如文档所述:
If one desires full control over input and output, then a scala.sys.process.ProcessIO can be used with 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 the tail command...
Such computation performed while tail was active!
Such computation performed while tail was active again!
boom
bar
cat
它仍然 return 立即,现在它只是挂在那里等待更多输入。如果我从 tmp
目录执行 echo 'fff' >> sample.txt
,程序输出:
Another computation!
Finished
您现在可以在发出 tail -f
命令后执行您想要的任何计算,并且可以根据您传递给 takeWhile
方法(或其他方法)的条件终止它关闭输入流)。
有关 ProcessIO
的更多详细信息,请查看 documentation here。
我认为,这与您向文件中添加数据的方式有关,与 ProcessBuilder
无关。例如,如果您在编辑器中使用它来添加数据,它会在您每次保存时使用不同的 inode 重写整个文件,而 tail
没有检测到这一点。
尝试 tail -F
而不是 tail -f
,应该可以。
当我编写以下代码时(在菊石中但我认为这不重要)
("tail -f toTail.txt" lineStream) foreach(println(_))
,程序按照预期给我最后一行但随后挂起,即使我在文件中写了更多内容,也没有任何结果。
API 如何支持具有无限输出的进程?
我试着写val myStream = ("tail -f toTail.txt" lineStream_!)
但它仍然没有return写掉
这是 scala 文档所说的内容:
lineStream: returns immediately like run, and the output being generated is provided through a Stream[String]. Getting the next element of that Stream may block until it becomes available.
所以我不明白为什么它会阻塞
顺便说一句,我和 Ammonite 的行为完全一样 API
如果再次输入 %%("tail", "-f", "toTail.txt")
该方法只是挂起,不会立即 return。
ProcessBuilder 没有问题(至少不是源于您的用例的问题)。来自 ProcessBuilder documentation:
Starting Processes
To execute all external commands associated with a ProcessBuilder, one may use one of four groups of methods. Each of these methods have various overloads and variations to enable further control over the I/O. These methods are:
- run: the most general method, it returns a scala.sys.process.Process immediately, and the external command executes concurrently.
- !: blocks until all external commands exit, and returns the exit code of the last one in the chain of execution.
- !!: blocks until all external commands exit, and returns a String with the output generated.
- lineStream: returns immediately like run, and the output being generated is provided through a Stream[String]. Getting the next element of that Stream may block until it becomes available. This method will throw an exception if the return code is different than zero -- if this is not desired, use the lineStream_! method.
文档明确指出 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_!
return 立即编辑了。因为命令的性质是有限的。
如何从产生无限输出的命令中立即return:
让我们用 tail -f
试试这个。您需要对流程进行更多控制。同样,正如文档所述:
If one desires full control over input and output, then a scala.sys.process.ProcessIO can be used with 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 the tail command...
Such computation performed while tail was active!
Such computation performed while tail was active again!
boom
bar
cat
它仍然 return 立即,现在它只是挂在那里等待更多输入。如果我从 tmp
目录执行 echo 'fff' >> sample.txt
,程序输出:
Another computation!
Finished
您现在可以在发出 tail -f
命令后执行您想要的任何计算,并且可以根据您传递给 takeWhile
方法(或其他方法)的条件终止它关闭输入流)。
有关 ProcessIO
的更多详细信息,请查看 documentation here。
我认为,这与您向文件中添加数据的方式有关,与 ProcessBuilder
无关。例如,如果您在编辑器中使用它来添加数据,它会在您每次保存时使用不同的 inode 重写整个文件,而 tail
没有检测到这一点。
尝试 tail -F
而不是 tail -f
,应该可以。