我使用popen3得到了意想不到的行为,我想用它来运行像tool ala cmd < file1 > file2这样的命令。下面的示例挂起,因此永远无法访问stdout done。使用cat以外的其他工具可能会导致挂起,因此永远无法访问stdin done。我怀疑,我正在遭受缓冲的痛苦,但我如何解决这个问题?
#!/usr/bin/env ruby
require 'open3'
Open3.popen3("cat") do |stdin, stdout, stderr, wait_thr|
stdin.puts "foobar"
puts "stdin done"
stdout.each_line { |line| puts line }
puts "stdout done"
puts wait_thr.value
end
puts "all done"发布于 2012-01-21 17:51:15
stdout.each_line正在等待cat的进一步输出,因为cat的输出流仍然打开。它仍然打开是因为cat仍在等待用户的输入,因为它的输入流尚未关闭(您会注意到,当您在终端中打开cat并键入foobar时,它仍将运行并等待输入,直到您按下^d关闭流)。
因此,要解决这个问题,只需在打印输出之前调用stdin.close即可。
发布于 2013-05-15 23:00:21
您的代码挂起,因为 stdin 仍处于打开状态!
您需要使用IO#close或IO#close_write关闭它,如果您使用的是popen3。
如果使用popen,则需要使用IO#close_write,因为它只使用一个文件描述符。
#!/usr/bin/env ruby
require 'open3'
Open3.popen3("cat") do |stdin, stdout, stderr, wait_thr|
stdin.puts "foobar"
stdin.close # close stdin like this! or with stdin.close_write
stdout.each_line { |line| puts line }
puts wait_thr.value
end另请参阅:
Ruby 1.8.7 IO#close_write
Ruby 1.9.2 IO#close_write
发布于 2014-11-02 07:09:30
Tilo和sepp2k的答案是正确的:如果你关闭了stdin,你的简单测试就会结束。问题解决了。
尽管在你对answer of sepp2k的评论中,你表明你仍然经历着挂起。好吧,这里有一些你可能忽略的陷阱。
stderr已满缓冲区卡住
如果您调用的程序打印到stderr的数量超过了匿名管道的缓冲区所能容纳的数量(对于当前Linuxes为64KiB),则该程序将挂起。挂起的程序既不退出也不关闭stdout。因此,从其stdout读取将挂起。因此,如果你想做正确的事情,你必须使用线程或IO.select,非阻塞,无缓冲的读取,以便并行或轮流从标准输出和标准错误读取,而不会被卡住。
在标准输入的满缓冲区上卡住
如果您尝试向程序(cat)提供比"foobar“更多(更多)的内容,则标准输出的匿名管道的缓冲区将被填满。操作系统将挂起cat。如果您向stdin写入更多内容,则stdin的匿名管道的缓冲区将被填满。那么你打给stdin.write的电话就会卡住。这意味着:您需要并行或轮流写入stdin、从stdout读取和从stderr读取。
结论
阅读一本好书(Richards Stevens,"UNIX网络编程:进程间通信“),并使用好的库函数。IPC (进程间通信)太复杂了,容易出现不确定的运行时行为。这是太麻烦了,试图让它正确的尝试和错误。
使用Open3.capture3。
https://stackoverflow.com/questions/8952043
复制相似问题