2009-11-27 55 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[@]}看到管道所有命令的退出代碼。