Perl:STDOUT 重新打开为 FH 仅用于输入

Perl: STDOUT reopened as FH only for input

我收到以下错误消息(使用 Perl 5):

Tools.pm: Filehandle STDOUT reopened as FH only for input at /usr/local/lib/perl5/site_perl/mach/5.20/Template/Provider.pm line 967.

我明白了原因:是STDOUT被关闭了,后来用同一个FD做了一些和STDOUT无关的事情。

代码做正确的事。唯一的问题是不应记录此错误消息。

如何停止将此错误消息打印到我们的日志文件中?

Template::Manual::Config::ERROR 中概述了错误的详细处理。

在构造函数中可以通过为异常类型指定模板来分类

my $template = Template->new({  
     ERRORS => {
         user     => 'user/index.html',
         dbi      => 'error/database',
         default  => 'error/default',
     },
});

可以使用 THROW 指令引发

[% THROW user.login 'no user id: please login' %]

或调用throw方法

$context->throw('user.passwd', 'Incorrect Password');  
$context->throw('Incorrect Password');    # type 'undef'

或通过调用 die 的 Perl 代码,可能使用 Template::Exception 对象。

如何使用这个来解决问题是一个细节问题,其中提供了none。

但您真的想找到触发它的(用户)代码并清理它。其一,正如 ikegami 在评论中指出的那样,不要关闭 STDOUT 而是将其重新打开到 /dev/null。 (我会说,永远不要简单地关闭标准流。)例如,如果您只是不想再看到 STDOUT

open STDOUT, '>', '/dev/null';

或在重新打开之前先复制它(使用 dup2)以便稍后恢复它

open my $SAVEOUT, '>&', 'STDOUT';
open STDOUT, '>', '/dev/null';
...
open STDOUT, '>', $SAVEOUT;  # restore STDOUT
close $SAVEOUT;              # if unneeded

(参见 open),或者如果可行,创建一个 local *FOO 并使用它来保存 STDOUT

这个警告是因为总是使用最低未使用的文件描述符,这里 fd 1 是通过关闭 STDOUT 腾出的;但它试图用于输入不正确的内容。至于为什么不行,为什么发出警告,this thread and an old bug report有用。这超越了 Perl。


一种通用方法是使用 __WARN__ hook

BEGIN {
    $SIG{__WARN__} = sub {
        warn @_ 
            unless $_[0] ~= /Filehandle STDOUT reopened as FH only for input/
    }
};

发出警告的位置,除非它与您要抑制的警告相匹配。 这个 BEGIN 块需要在它预期影响的模块的 use 语句之前。如果您知道需要它的范围,最好将其本地化,local $SIG{__WARN__} = sub {...};

有关更多详细信息,请参阅 及其指向其他帖子和相关文档的链接。