2009-11-27 64 views
32

我有一个Broken pipe (Errno::EPIPE)错误弹出,我不明白它是什么或如何解决它。完整的错误是:我的代码破管(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") 

回答

21

这意味着,无论连接打印的输出到不再连接。据推测,该计划开始输入到其他程序:

% ruby_program | another_program 

什么事是another_program已经有问题的print之前的某个时候退出。

+0

实际上,这段代码都是针对http请求的。这是否意味着服务器在那时没有连接?这似乎是随机发生的。 – sepiroth 2009-11-27 08:23:57

+0

我对ruby不太了解,但EPIPE可能会造成网络断开。在Linux上,我预计这种情况下的错误可能是ENETRESET,ECONNABORTED,ECONNRESET,ENOTCONN或ESHUTDOWN。 – wallyk 2009-11-27 09:01:17

+1

@sepiroth:'EPIPE'是_system_-defined;它是系统调用报告的退出代码,它触发了'SIGPIPE'信号,这通常表明_pipe_的_reading_端处的进程已退出(而_writing_端仍在尝试写入管道);另外,在_network_上下文中, [this](https://www.gnu.org/software/libc/manual/html_mono/libc.html#Operation-Error-Signals)指出:“SIGPIPE的另一个原因是当您尝试输出到未连接的_socket_时,请参阅[发送数据](https://www.gnu.org/software/libc/manual/html_mono/libc.html#Sending-Data)“。 – mklement0 2015-05-07 13:09:41

12

@wallyk是对的问题。一个解决方案是用Signal.trap捕捉信号:

Signal.trap("PIPE", "EXIT") 
9

虽然信号陷阱做工作,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在评论中一样),如果你最初管道使用看跌期权的东西你的输出期望在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 
+0

+1合理的建议 – tokland 2014-08-22 09:52:49

+1

听起来很明智,但在实践中(Ruby 2.0.0)我一直无法捕捉到这个错误;尝试'ruby -e'开始; puts(1..10000).map {| n | “line#{n}”};救援Errno :: EPIPE; “不可以:#{$ !. message}”;结束'|头“ - 它仍然打破;即使试图拯救'Exception'也不行。有什么我失踪? – mklement0 2015-05-07 12:51:15

+2

@ mklement0您实际上正在拯救该异常,但是在您的救援声明中再次引发了异常,因为您正在尝试将自定义异常字符串写入STDOUT,该STDOUT仍处于管理状态(并且其管道已经断开) 。如果你运行这个'ruby -e'begin; puts(1..10000).map {| n | “line#{n}”};救援Errno :: EPIPE; STDERR.puts“No can do:#{$ !. message}”;结束'|头部,你会发现它确实拯救了原始的Errno :: EPIPE异常。 – 2015-05-07 21:40:22

6

以下主要适用于设计成用作的CLI Ruby脚本; CLI通常只需要在收到SIGPIPE时安静地终止,具体退出代码为;对于需要逐个处理SIGPIPE的脚本,请考虑donovan.lampa's helpful answer

为了补充wallyk's helpful answertokland's helpful answer

如果你希望你的脚本展览系统的默认行为,为大多数Unix工具(例如,cat)做,使用

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

在您的脚本开始。

现在,当你的脚本接收SIGPIPE信号(在类Unix系统),该系统的默认行为:

  • 悄然终止脚本
  • 报告退出代码141(其计算为128(表示通过信号终止)+ 13SIGPIPE号码))

相反,Signal.trap("PIPE", "EXIT")将报告退出代码0

注意,在背景下,退出代码往往不是在诸如ruby examble.rb | head命令明显,因为shell(默认情况下)只报告最后命令的退出代码。

bash,您可以检查${PIPESTATUS[@]}看到管道所有命令的退出代码。