设置一个文件句柄以便悄悄地跳过打印到它的文件?

Set a filehandle so that prints to it are quietly skipped?

这种奇怪的兴趣来自不断扩大的需求,没有时间更改设计(重构)。这当然不是好的设计,但我现在需要处理它,希望以后能重构。

有一些早期打开的日志文件被打印到整个代码中。新要求意味着使用(新)命令行选项 (--noflag) 这些日志文件之一是无关紧要的。

目前我所能做的就是填充定义 (open my $fh, ...) 并且 所有使用 (print $fh ...) 的 [=13] =].这显然是糟糕的设计,而且容易出错(也不漂亮)。

有没有办法在 $fh 与文件相关联时对其进行处理 这样任何以下 print $fh ... 都会被解释器接受,但只会导致 运行 宁 print,没有错误? (让我想象一下,比如 $fh = VOID if $flag;。)或者,是否有一些 NULL 流或类似的东西?我只知道 STDOUT (1)、STDERR (2) 和 STDIN (0)。

我不希望 $fh 打印到其他任何地方,最好甚至不打印到 /dev/null(如果可能的话?)。我确实环顾四周,找不到任何相关的东西。如果事实上它已经存在,我将不胜感激。 任何想法表示赞赏。

PS。在这里问的第一个问题(经过多年使用 SO),请告诉我它是否关闭。


更新

感谢您的回复。他们提示我添加 to/refine 这个问题:标记为 /dev/null 的打印是否可能已优化,以便 'printing' 实际上不会发生? (虽然我仍然对是否可以设置文件句柄以便告诉 Perl 'do not print here' 感兴趣。)

我正在尝试避免 运行ning void (print) 语句,而不添加条件。


Update/Clarification

从评论中总结一下(谢谢!):这不是对性能优化的追求。我完全同意评论中所说的一切。只是执行无意义的语句(通常大约一百万)让我感到不安。另外,我很好奇 Perl 的一些可能的黑暗角落,我没有 运行 进入。 (其中大部分已在 answers/comments 中解决。)

如果您使用的是 unix 操作系统,您可以使用“/dev/null”

open my $fh, '>', '/dev/null' or die 'This should never happen';

Dev null 将静默接受所有输入。

您可以像这样使用 an anonymous, temporary file(大约在 perldoc 页面的四分之一处);

#!/usr/bin/env perl
use strict;
use Getopt::Long;

my $fh;
my $need_log = 2;
print "Intitial need_log: $need_log\n";

GetOptions('flag!' => $need_log);
print "After option processing, need_log: ", $need_log, "\n";

if ($need_log) {
  open($fh, '>', "log.txt") or die "Failed to open log: $!\n";
}
else {
  open($fh, '>', undef);
}

print $fh "Hello World... NOT\n";
exit 0;

这里有一些不同使用 --flag 选项的运行;

User@Ubuntu:~$ ls -l log.txt
ls: cannot access log.txt: No such file or directory
User@Ubuntu:~$ ./nf.pl
Intitial need_log: 2
After option processing, need_log: 2
User@Ubuntu:~$ cat log.txt
Hello World... NOT
User@Ubuntu:~$ rm log.txt
User@Ubuntu:~$
User@Ubuntu:~$
User@Ubuntu:~$ ./nf.pl --flag
Intitial need_log: 2
After option processing, need_log: 1
User@Ubuntu:~$ cat log.txt
Hello World... NOT
User@Ubuntu:~$ rm log.txt
User@Ubuntu:~$
User@Ubuntu:~$
User@Ubuntu:~$ ./nf.pl --noflag
Intitial need_log: 2
After option processing, need_log: 0
User@Ubuntu:~$ cat log.txt
cat: log.txt: No such file or directory
User@Ubuntu:~$

我已经将 $need_log 变量初始化为 '2' 这样我们就可以判断它是否有 'True' 值作为存在 flag 选项的结果(在这种情况下它将具有值 1)或作为没有提及标志选项的结果完全没有(在这种情况下它将具有值 2)。

指定 '--noflag' 触发 else 子句,该子句将 'undef' 作为创建 匿名临时文件。 这并不完全符合您根本不写的问题,但如果该文件是临时文件并且您没有在其中放入千兆字节,那么这就足够了。

通过魔法,你可以创造一个神奇的句柄,它的操作总是成功的。

perl -e'
   {
      package Handle::Dummy;
      use Tie::Handle qw( );
      use Symbol qw( gensym );
      our @ISA = qw( Tie::Handle );
      sub new { my $fh = gensym; tie *$fh, $_[0]; $fh }
      sub TIEHANDLE { bless(\my $dummy, $_[0]) }
      sub READ  { return 1; }
      sub WRITE { return 1; }
      sub CLOSE { return 1; }
   }

   my $fh = Handle::Dummy->new();   
   print($fh "abc\n") or die $!;
   close($fh) or die $!;
   print("ok\n");
'
ok

这避免了系统调用,但用昂贵的 Perl 子例程调用代替了它们。

使用/dev/null[1]更简单可靠[1]。它也可以更快。


Are prints marked to go to /dev/null possibly optimized

没有。 Perl 对 /dev/null.

一无所知

您认为系统调用有多慢?这听起来不像是优化的正确方法!


  1. 神奇的文件句柄与系统文件句柄无关,因此无法传递给 C 库,无法保存 exec,等等

正在关闭您的文件句柄

close $fh;

将使您对该文件句柄的所有 prints 失败。 运行

no warnings 'closed';

抑制所有可能生成的警告消息(你这样做 use warnings,对吧?)