我弹出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")
答案 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 answer和tokland'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
。