Ruby 如何实时获得 stdout 里的内容?

nine · 2014年12月16日 · 最后由 h_minghe 回复于 2014年12月18日 · 3101 次阅读

run.rb

puts  ·ruby sleep.rb·

sleep.rb

10.times do |t|
  p t
  sleep 1
end

运行 ruby run.rb 的时候需要 10 秒之后才能打印出信息,而不是每秒打印一个。

真实的需求是在 web 上 textarea 里输入 sleep.rb 的内容,并实时在另一个 texarea 里看到类似 console 里执行的效果 最好可以终止代码运行

'ruby sleep.rb' 是单独的进程了,run.rb call 它的时候是获取其的全部的 STDOUT,当然要等它结束之后才能获得。 你可以用管道来解决吧。

试试 $stdout.sync = true

#2 楼 @honryou 这个不行啊。

#1 楼 @h_minghe 非科班出身,对管道真心搞不太明白,能否指点一二?

找到解决办法了 用 pty http://stackoverflow.com/questions/1154846/continuously-read-from-stdout-of-external-process-in-ruby

require 'pty'
begin
  PTY.spawn( "ruby output.rb" ) do |stdin, stdout, pid|
    p pid
    begin
      stdin.each do |line| 
        p line.strip 
      end
    rescue Errno::EIO
    end
  end
rescue PTY::ChildExited
  puts "The child process exited!"
end

用 IO 库不太完美,可以执行字符串脚本,但是不能执行文件脚本 http://stackoverflow.com/questions/10224481/running-a-command-from-ruby-displaying-and-capturing-the-output

不用那么麻烦。

# cat o.rb
$stdout.sync = true
(1..10).each do |i|
  $stdout.puts i
  sleep 1
end
# cat i.rb
while line = $stdin.gets
  puts line
end

$ ruby o.rb | ruby i.rb

也可以用一个 Ruby 进程里,自己开两个管道,一个读一个写,推荐 Eric Wong 的这篇文章: http://blog.rubybestpractices.com/posts/ewong/010-An-introduction-to-the-Unix-pipe.html http://blog.rubybestpractices.com/

@nine @hooopo 命名管道最适合。

写进程 $ cat writer.rb

require "mkfifo"

if File.pipe?("named_pipe") || File.mkfifo("named_pipe")
  File.open("named_pipe", "w+") do |file|
    10.times do |t|
        file.puts "2"
        file.flush
        sleep 1
    end
  end
end

读进程 $ cat reader.rb

file = File.open("named_pipe", 'r+')
while !file.eof?
   line = file.readline
   puts line
end
需要 登录 后方可回复, 如果你还没有账号请 注册新账号