如何将Ruby脚本的输出管道输出到"head"而不会出现管道错误

dan*_*dan 17 ruby unix pipe

我有一个简单的Ruby脚本,看起来像这样

require 'csv'
while line = STDIN.gets
  array = CSV.parse_line(line)
  puts array[2]
end
Run Code Online (Sandbox Code Playgroud)

但是当我尝试在这样的Unix管道中使用这个脚本时,我得到10行输出,然后是一个错误:

ruby lib/myscript.rb < data.csv  | head

12080450
12080451
12080517
12081046
12081048
12081050
12081051
12081052
12081054
lib/myscript.rb:4:in `write': Broken pipe - <STDOUT> (Errno::EPIPE)
Run Code Online (Sandbox Code Playgroud)

有没有办法以防止破坏管道异常的方式编写Ruby脚本?

Phi*_*oss 22

head在读取了所需的所有数据后关闭标准输出流.您应该处理异常并停止写入标准输出.一旦标准输出关闭,以下代码将中止循环:

while line = STDIN.gets
  array = CSV.parse_line(line)
  begin
    puts array[2]
  rescue Errno::EPIPE
    break
  end
end
Run Code Online (Sandbox Code Playgroud)

  • @ sepp2k - 这里有很多事情要发生:1,stdout的默认缓冲模式在使用管道时从面向行变为面向块,因此你需要在每次写入之间进行刷新.2,`head`需要有机会运行以关闭流,但是在它有机会运行之前可能已经写了更多字节的数据.我用`$ stdout.flush写了一个脚本的变体; 在每个`write`之间睡眠0.1`,在这种情况下`$ stdout.closed?`有效. (5认同)

Jon*_*ler 10

我使用的技巧是替换headsed -n 1,10p.

这使管道保持打开状态ruby(或任何其他测试管道损坏和抱怨的程序)不会破坏管道,因此不会抱怨.为行数选择所需的值.

显然,这不是试图修改您的Ruby脚本.几乎可以肯定有一种方法可以在Ruby代码中实现.但是,即使您无法修改生成消息的程序,"sed而不是head"技术仍然有效.