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

问题描述 投票:13回答:3

我正在编写一些带有文件的代码,将该文件传递给多个二进制文件之一进行处理,并监视转换过程中的错误。我已经在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没有发送eof up the pty。 PTY文档页面和ruby-doc上的IO似乎没有任何帮助。

有什么建议?谢谢。

-vox-

ruby debian ruby-1.9.3 pty
3个回答
17
投票

因此,我必须尽量读取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上完全没有记录。


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版本和平台。


0
投票

ruby-doc.org从红宝石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来读取chunk的内容块。即使这样,如果由于某种原因不以“\ n”结尾,你也有可能失去最后一行。为了更加安全,您需要使用m.read(1)逐字节读取内容

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

© www.soinside.com 2019 - 2024. All rights reserved.