奇怪的Perl SIGPIPE行为(“ IGNORE”有效,sub无效)

时间:2018-09-23 11:52:29

标签: perl runtime-error signals warnings perl5

如对这些问题的评论所述:

<!DOCTYPE html> <html> <head> <title>Page Title</title> </head> <body> <h1>Page cahced yet</h1> <p>This is a paragraph.</p> </body> </html>

产生错误消息perl -e '$SIG{PIPE} = "IGNORE"; sleep(1); print "foo\n";' | echo -n

但是很奇怪

Unable to flush stdout: Broken pipe

不产生任何消息。

第二个命令为什么不产生消息?如何赶上SIGPIPE事件?

我真正需要的是(为了回答this question的实验)来捕获SIGPIPE,并在发生时将某些内容输出到日志文件中。

1 个答案:

答案 0 :(得分:2)

在像示例中那样写入管道时,默认情况下会缓冲STDOUT。这意味着代码中的print "foo\n"不会立即写入STDOUT,而是写入缓冲区,并且只有在缓冲区已满或作为程序清理的一部分时,才会刷新缓冲区(写入STDOUT)。使用strace来查看您的程序实际上在做什么,这表明它首先将信号处理程序作为程序清理的一部分还原,然后写入STDOUT,从而导致SIGPIPE不再由您的子程序处理,因此导致杀死程序。

当确保立即完成输出而不是在程序清除时进行输出时,信号处理程序将被成功触发。这可以通过使用$|=1使STDOUT无缓冲来实现:

$ perl -e \
   '$|=1; $SIG{PIPE} = sub { print STDERR "XXX\n"; }; sleep(1); print "foo\n";' \
   | echo -n

output: XXX

换句话说:如果激活,则信号处理程序将完美运行,并且它只是触发了您特定用途的人工制品。关于为什么它在退出时没有将信号处理程序从忽略(SIG_IGN)重置为默认(SIG_DFL)的问题,因此显示了我不知道的IGNORE相同的问题。