代码之家  ›  专栏  ›  技术社区  ›  porton

奇怪的PerlSigPipe行为(“忽略”工作,Sub不工作)

  •  0
  • porton  · 技术社区  · 6 年前

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

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

    生成错误消息 Unable to flush stdout: Broken pipe .

    但奇怪的是

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

    不产生任何消息。

    为什么第二个命令不生成消息?如何捕获sigpipe事件?

    我真正需要的是(一个实验来回答 this question )捕捉sigpipe,当它发生时,输出一些东西到日志文件。

    1 回复  |  直到 6 年前
        1
  •  2
  •   Steffen Ullrich    6 年前

    当像在示例中一样写入管道时,默认情况下会缓冲stdout。这意味着 print "foo\n" 在您的代码中,不会立即写入stdout,而是写入缓冲区,只有当缓冲区已满或作为程序清理的一部分时,缓冲区才会被刷新(写入stdout)。使用 strace 要查看您的程序实际执行的操作,它首先将信号处理程序还原为程序清理的一部分,然后写入stdout,从而导致sigpipe不再由Sub处理,从而导致程序终止。

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

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

    换句话说:如果活动的话,您的信号处理程序工作得很好,而且它只是您特定用途的产物,所以没有被触发。关于它为什么不从忽略重置信号处理程序( SIG_IGN )违约( SIG_DFL )在出口,因此显示了相同的问题与忽略,我不知道。