我在解决我的这个问题上取得了一些成功。如果有类似问题的任何人找到此页面,这里是详细信息,并带有一些解释。但是,如果您不在乎细节,这是一个简短的答案:
以下列方式使用PTY.spawn(当然要使用您自己的命令):
require 'pty'
cmd = "blender -b mball.blend -o //renders/ -F JPEG -x 1 -f 1"
begin
PTY.spawn( cmd ) do |stdout, stdin, pid|
begin
stdout.each { |line| print line }
rescue Errno::EIO
puts "Errno:EIO error, but this probably just means " +
"that the process has finished giving output"
end
end
rescue PTY::ChildExited
puts "The child process exited!"
end
而这里的长的答案,有太多的细节:
真正的问题似乎是,如果某个进程没有显式刷新其stdout,则将写入stdout的所有内容缓冲起来而不是实际发送,直到该进程完成为止,以最大程度地减少IO(这显然是许多实现的细节C库,可以通过较少的IO来最大化吞吐量。如果您可以轻松地修改该过程以使其定期刷新stdout,那么这将是您的解决方案。在我的情况下,它是搅拌机,因此对于像我这样的完整菜鸟修改源代码有点吓人。
但是,当您从外壳程序运行这些进程时,它们会实时向外壳程序显示stdout,并且stdout似乎没有被缓冲。我相信只有从另一个进程调用时,它才会被缓冲,但是如果要处理一个shell,则可以无缓冲地实时看到stdout。
甚至可以将ruby进程作为子进程来观察此行为,因为该子进程必须实时收集其输出。只需创建带有以下行的脚本random.rb:
5.times { |i| sleep( 3*rand ); puts "#{i}" }
然后一个ruby脚本调用它并返回其输出:
IO.popen( "ruby random.rb") do |random|
random.each { |line| puts line }
end
您会看到,您无法像预期的那样实时获得结果,但是此后立即全部获得。STDOUT正在缓冲,即使您自己运行random.rb也不缓冲。这可以通过STDOUT.flush
在random.rb中的块内添加一条语句来解决。但是,如果您无法更改源,则必须解决此问题。您不能从过程外部刷新它。
如果子进程可以实时打印到shell,那么还必须有一种使用Ruby实时捕获它的方法。还有。我必须使用红宝石内核中包含的PTY模块(无论如何仍为1.8.6)。可悲的是,它没有记录在案。但是我幸运地找到了一些使用的例子。
首先,解释什么是PTY,它代表伪终端。基本上,它允许ruby脚本将自身呈现给子进程,就好像它是在命令行中键入命令的真实用户一样。因此,仅当用户通过外壳启动进程时(例如,STDOUT未缓冲),才会发生任何更改的行为。隐藏另一个进程已启动的事实,该进程使您可以实时收集STDOUT,因为它没有被缓冲。
要使用random.rb脚本作为子代,请尝试以下代码:
require 'pty'
begin
PTY.spawn( "ruby random.rb" ) do |stdout, stdin, pid|
begin
stdout.each { |line| print line }
rescue Errno::EIO
end
end
rescue PTY::ChildExited
puts "The child process exited!"
end