Ruby on Linux PTY在没有EOF的情况下消失,引发了Errno :: EIO

时间:2012-04-19 23:29:40

标签: ruby debian ruby-1.9.3 pty

我正在编写一些带有文件的代码,将该文件传递给多个二进制文件之一进行处理,并监视转换过程中的错误。我已经在OSX上编写并测试了以下例程,但是由于我不清楚的原因,linux失败了。

#run the command, capture the output so it doesn't display
PTY.spawn(command) {|r,w,pid|
    until r.eof? do
      ##mark
      puts r.readline
    end
}

运行的命令变化很大,##标记处的代码已简化为本地回显以尝试调试问题。该命令执行,脚本在终端中打印预期的输出,然后抛出异常。

它在Debian系统上产生的错误是:Errno::EIO (Input/output error - /dev/pts/0):

我可以提出的所有命令字符串都会产生错误,当我运行没有本地echo块的代码时,它运行得很好:

PTY.spawn(command) {|r,w,pid|}

在任何一种情况下,命令本身都可以正常执行,但似乎debian linux并没有向pof发送eof。 PTY文档页面和ruby-doc上的IO似乎没有任何帮助。

有什么建议吗?感谢。

-vox -

3 个答案:

答案 0 :(得分:16)

因此,我必须尽量阅读PTY库的C源,以便对此处发生的事情感到非常满意。

Ruby PTY文档并没有真正说出评论in the source code所说的内容。

我的解决方案是组合一个包装器方法,并在需要时从我的脚本中调用它。我还装入等待进程的方法,以确保退出并从$?访问退出状态:

# file: lib/safe_pty.rb

require 'pty'
module SafePty
  def self.spawn command, &block

    PTY.spawn(command) do |r,w,p|
      begin
        yield r,w,p
      rescue Errno::EIO
      ensure
        Process.wait p
      end
    end

    $?.exitstatus
  end
end

这与PTY.spawn基本相同:

require 'safe_pty'
exit_status = SafePty.spawn(command) do |r,w,pid|
  until r.eof? do
    logger.debug r.readline
  end
end

#test exit_status for zeroness

我发现这是一个有效的回复我感到有点沮丧,因为它在ruby-doc上完全没有记录。

答案 1 :(得分:5)

在这里提出Errno :: EIO似乎是有效的(它只是意味着子进程已经完成并关闭了流),所以你应该期待并抓住它。

例如,请参阅Continuously read from STDOUT of external process in Rubyhttp://www.shanison.com/2010/09/11/ptychildexited-exception-and-ptys-exit-status/

中的所选答案 顺便说一下,我做了一些测试。在Ubuntu 10.04上的Ruby 1.8.7上,我没有收到错误。使用Ruby 1.9.3,我做到了。在1.8和1.9模式的Ubuntu上使用JRuby 1.6.4,我没有收到错误。在OS X上,1.8.7,1.9.2和1.9.3,我没有收到错误。这种行为显然取决于您的Ruby版本和平台。

答案 2 :(得分:0)

ruby​​-doc.org从ruby 1.9开始这样说:

# The result of read operation when pty slave is closed is platform
# dependent.
ret = begin
        m.gets          # FreeBSD returns nil.
      rescue Errno::EIO # GNU/Linux raises EIO.
        nil
      end

好吧,所以现在我知道这种行为在Linux上是“正常”的,但这意味着获取PTY的输出有些棘手。如果执行m.read,它将读取所有内容,然后将其丢弃并引发Errno :: EIO。您确实需要使用m.readline逐块读取内容。即使这样,如果由于某种原因它没有以“ \ n”结尾,也可能会丢失最后一行。为了更加安全,您需要使用m.read(1)

逐字节读取内容

关于tty和pty对缓冲的影响的附加说明:它与子进程中的STDOUT.sync = true(非缓冲输出)不同,而是触发行缓冲,其中输出在“ \ n”上刷新