2011-08-19 60 views
7

我正在使用IO.popen打开另一个程序,并不断地读取数据的脚本。它是这样的:红宝石IO.popen标准输出缓冲

process = IO.popen(["/the/program", "argument", "argument"]) 

loop do 
    line = process.gets 
    puts "#{line}" 
end 

(实际计划并不仅仅是打印输出,显然更多 - 这只是一个例子。)

我遇到的问题是,POPEN似乎缓冲STDOUT从开放的过程。我已经通过直接从shell运行程序并通过popen并行执行来确认这一点,并且Ruby一次从来没有获得一行。它一次获取多行,并且延迟。

我已经试过

STDOUT.sync = true 

... POPEN之前,但是这并没有改变任何东西。

有问题的程序肯定是使用\ n作为新行,所以这不是问题。

+0

你试过'process.sync = true'吗? – DNNX

+0

@Eddie你知道了吗? –

回答

5

你有源头到其他程序?您需要强制其他程序清除其输出,或者使脚本看起来像一个pty(请参阅pty标准库)。

对正在发生的事情的一个很好的说明,请参见this question

EDIT:PTY代码示例:

require 'pty' 
PTY.spawn "some-command" do |r,w,p| 
    loop { puts r.gets } 
end 
+0

如果不以换行符结束,则不能打印最后一行(例如,某些命令是echo -n ABC)。 –

3

我怀疑/the/program是缓冲当它检测stdout不是终端 - 你可以通过猫管道测试,例如:

"/the/program" "argument" "argument" | cat 

上面的答案,将解决这个问题如果是这样的问题,即:

#!/usr/bin/env ruby 

require 'pty' 
PTY.spawn "./the-program testing one Two three" do |r,w,p| 
    loop { puts "GOT: #{r.gets}" } 
end 

某些语言(例如C)检测是否stdout是终端,切换到行缓冲 - 见Is stdout line buffered, unbuffered or indeterminate by default?

作为一个例子时,它的工作原理,我使用的一个简单的bash脚本来输出每个参数和时间,一个在一个时间与之间的3秒和红宝石脚本工作没有问题。我为这个例子添加了eof检测。

修改后的脚本:

#!/usr/bin/env ruby 

process = IO.popen(["./the-program", "testing", "one", "Two", "three"]) 

while !process.eof? 
    line = process.gets 
    puts "GOT: #{line}" 
end 

的节目内容:

#!/bin/bash 

for arg 
do 
    echo $arg 
    date 
    sleep 3 
done 

我用Ruby版本1.9.3和2.1.2

$ ruby ,p 
GOT: testing 
GOT: Mon Jun 16 06:19:00 EST 2014 
GOT: one 
GOT: Mon Jun 16 06:19:03 EST 2014 
GOT: Two 
GOT: Mon Jun 16 06:19:06 EST 2014 
GOT: three 
GOT: Mon Jun 16 06:19:09 EST 2014 
$ 

尝试。如果我使用C程序,不是,那么问题重新出现:

#include <stdio.h> 

main(int argc, char **argv) 
{ 
     int i; 

     for (i=0; i<argc; i++) { 
       printf("%s\n", argv[i]); 
       sleep(3); 
     } 
}