什么是红宝石的管道方式?

时间:2016-02-03 21:55:02

标签: ruby pipe ipc jruby

我在Ruby中构建一个程序,必须在其他程序中阅读' stdout并向stdin发送一些文字。我找到的当前解决方案是使用JRuby并使用一些熟悉的Java函数来完成任务。是否还有一个纯Ruby解决方案?

require 'java'

java_import java.lang.ProcessBuilder
java_import java.io.PrintStream
java_import java.util.Scanner

process = ProcessBuilder.new("bc", "-i").start
Thread.new {
    input = Scanner.new(process.input_stream)
    while input.has_next_line? do
        puts("<- bc: " + input.next_line)
    end
}
output = PrintStream.new(process.output_stream)
loop do
    s = gets.chomp
    if s == "exit"
        break
    end
    output.println(s)
    output.flush
end

程序运行

<- bc: bc 1.06.95
<- bc: Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
<- bc: This is free software with ABSOLUTELY NO WARRANTY.
<- bc: For details type `warranty'.
1+1
<- bc: 1+1
<- bc: 2
<- bc:
2*3
<- bc: 2*3
<- bc: 6
<- bc:
exit

1 个答案:

答案 0 :(得分:0)

如果你想读取程序的输出,那么最好的办法就是产生一个伪终端(pty),这样它的输出就是行缓冲的。幸运的是,使用Ruby的PTY模块非常容易。在示例中,我使用IO.select和非阻塞调用来避免线程。

#!/usr/bin/env ruby
require 'pty'

r, w, pid = PTY.spawn('bc -i')
running = true

while running
  fds = IO.select([$stdin, r])

  # fds[0] is an array of IO objects that are ready to be read from
  fds[0].each do |fd|
    if fd == r
      output = r.read_nonblock(1024)
      output.split("\n").each { |l| puts '<- bc: ' + l }
    elsif fd == $stdin
      line = $stdin.gets.strip
      if line == 'exit'
        running = false
        break
      end

      w.write_nonblock(line + "\n")
    end
  end
end

Process.kill("TERM", pid)
Process.waitpid(pid)

输出,

<- bc: bc 1.06.95
<- bc: Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
<- bc: This is free software with ABSOLUTELY NO WARRANTY.
<- bc: For details type `warranty'.
<- bc:
1+1
<- bc: 1+1
<- bc: 2
2*3
<- bc: 2*3
<- bc: 6
exit