破管(Errno :: EPIPE)

时间:2009-11-27 08:11:16

标签: ruby

我弹出Broken pipe (Errno::EPIPE)错误,我不明白它是什么或如何解决它。完整的错误是:

example.rb:19:in `write': Broken pipe (Errno::EPIPE)
    from example.rb:19:in `print'
    from example.rb:19

我的代码的第19行是:

vari.print("x=" + my_val + "&y=1&z=Add+Num\r\n")

4 个答案:

答案 0 :(得分:23)

这意味着输出的任何连接打印都不再连接。据推测,该计划开始作为其他计划的输入:

 % ruby_program | another_program

发生的事情是another_program已在print之前的某个时间退出。

答案 1 :(得分:14)

@wallyk是对的。一种解决方案是使用Signal.trap

捕获信号
Signal.trap("PIPE", "EXIT")

答案 2 :(得分:12)

虽然信号陷阱确实有效,但是像tokland所说,它们是在应用程序范围内定义的,如果你想在应用程序的其他地方以其他方式处理损坏的管道,它们可能会导致一些意想不到的行为。

我建议只使用标准救援,因为错误仍然继承自StandardError。有关此错误模块的更多信息:http://ruby-doc.org/core-2.0.0/Errno.html

示例:

begin
  vari.print("x=" + my_val + "&y=1&z=Add+Num\r\n")
rescue Errno::EPIPE
  puts "Connection broke!"
end

编辑:重要的是要注意(正如评论中的@ mklement0所做的那样)如果您最初使用puts将输出用于STDOUT上的输出,那么上面代码中的最终输入将是引发另一个Errno :: EPIPE异常。无论如何,使用STDERR.puts可能是更好的做法。

begin
  vari.print("x=" + my_val + "&y=1&z=Add+Num\r\n")
rescue Errno::EPIPE
  STDERR.puts "Connection broke!"
end

答案 3 :(得分:8)

注意:

  • 第1部分适用于设计用作基于终端的命令行实用程序 的Ruby脚本,假设他们要求无自定义接收SIGPIPE 时处理或清理,并假设您希望它们展示标准Unix实用程序的行为,例如cat,其中 静默终止在收到SIGPIPE时带有特定退出代码

  • 第2部分适用于需要{em>自定义处理 SIGPIPE的脚本,例如显式清理和(有条件的)输出错误消息

选择加入SIGPIPE系统默认处理

补充wallyk's helpful answertokland's helpful answer

如果您希望脚本展示系统的默认行为,那么大多数Unix实用程序(例如cat)都可以,使用

Signal.trap("SIGPIPE", "SYSTEM_DEFAULT") 

在脚本的开头。

现在,当您的脚本收到SIGPIPE信号(在类Unix系统上)时,系统的默认行为将为:

  • 悄悄终止您的脚本
  • 报告退出代码141 (计算为128(表示通过信号终止)+ 13({{ 1}}' s number ))

(相比之下,SIGPIPE会在收到信号时报告退出代码Signal.trap("PIPE", "EXIT"),表示成功。)

请注意,在 shell 上下文中,退出代码在0等命令中通常不明显,因为shell(默认情况下)仅报告 last 命令的退出代码。

ruby examble.rb | head中,您可以检查bash以查看管道中所有命令的退出代码。

最小示例(从${PIPESTATUS[@]}运行):

bash

Ruby代码尝试输出100,000行,但ruby -e "Signal.trap('PIPE','SYSTEM_DEFAULT');(1..1e5).each do|i| puts i end" | head 仅输出前10行然后退出,这将关闭连接两个命令的管道的读取端。

下一次Ruby代码尝试写入现在已经断开的管道的写入结束时(在填充管道缓冲区之后),它会触发信号head,它会悄悄地终止Ruby进程,退出代码为{{1之后您可以使用SIGPIPE进行验证。

相比之下,如果您删除了141,即使用Ruby的默认行为,该命令会大声破坏(几行stderr输出),退出代码将是不起眼的echo ${PIPESTATUS[0]}

自定义处理Signal.trap('PIPE','SYSTEM_DEFAULT')

以下内容基于donovan.lampa's helpful answer,并添加了一项改进建议  Kimmo Lehto,谁指出,取决于您的脚本的目的,接收1不应该总是静静地,因为它可能表明合法错误条件 ,特别是在网络代码中,例如从互联网下载文件的代码。
他为这种情况推荐了以下习语:

SIGPIPE

作为一个单行:

SIGPIPE

注意:抢救begin # ... The code that could trigger SIGPIPE rescue Errno::EPIPE # ... perform any cleanup, logging, ... here # Raise an exception - which translates into stderr output - # but only when outputting directly to a terminal. # That way, failure is quiet inside a pipeline, such as when # piping to standard utility `head`, where SIGPIPE is an expected # condition. raise if $stdout.tty? # If the stack trace that the `raise` call results in is too noisy # use something like the following instead, which outputs just the # error message itself to stderr: # $stderr.puts $! if $stdout.tty? # Or, even simpler: # warn $! if $stdout.tty? # Exit with the usual exit code that indicates termination by SIGPIPE exit 141 end 有效,因为如果信号被忽略,系统调用写入管道将返回给调用者(而不是调用者进程已终止< / em>),即标准错误代码 ... rescue Errno::EPIPE raise if $stdout.tty?; exit 141 ,Ruby表面异常为Errno::EPIPE