我正在编写一些带有文件的代码,将该文件传递给多个二进制文件之一进行处理,并监视转换过程中的错误。我已经在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 -
答案 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 Ruby和http://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”上刷新