我正在编写一些带有文件的代码,将该文件传递给多个二进制文件之一进行处理,并监视转换过程中的错误。我已经在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-
因此,我必须尽量读取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上完全没有记录。
在这里提出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版本和平台。
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”上刷新