5

我想抑制子进程中的输出并只读stderr。perlfaq8建议执行以下操作:

# To capture a program's STDERR, but discard its STDOUT:
use IPC::Open3;
use File::Spec;
use Symbol qw(gensym);
open(NULL, ">", File::Spec->devnull);
my $pid = open3(gensym, ">&NULL", \*PH, "cmd");
while( <PH> ) { }
waitpid($pid, 0);

但随后perlcritic争论使用裸字文件句柄

我唯一能设计的是将select新打开的描述符/dev/null改为 on STDOUT,如下所示:

# To capture a program's STDERR, but discard its STDOUT:
use IPC::Open3;
use File::Spec;
use Symbol qw(gensym);
open my $null, ">", File::Spec->devnull;
my $old_stdout = select( $null );
my $pid = open3(gensym, ">&STDOUT", \*PH, "cmd");
select( $old_stdout );
while( <PH> ) { }
waitpid($pid, 0);

但是perlcritic不喜欢使用 ofselect。有更优雅的解决方案吗?

4

3 回答 3

3

最小的改变只是通过将它更改为 *NULL 来使 open 中的 NULL 不再是一个裸词。

使用这种形式的句柄通常仍然被认为是糟糕的形式(因为它们是全局变量,尽管您可以通过对它们应用局部来使它们的全局性降低一些)。因此,我建议将其更改为将我的变量用于所有句柄。看起来您正在丢弃标准输入文件句柄,因此也可以传递空文件句柄(注意我以读写模式打开它)

use strict;
use warnings;

use IPC::Open3;
use File::Spec;
use Symbol qw(gensym);

open(my $null, '+>', File::Spec->devnull);

my $childErr = gensym;

my $pid = open3($null, $null, $childErr, "cmd");

while(<$childErr>) { }
waitpid($pid, 0);
于 2013-12-05T07:38:28.240 回答
3
  • select实际上什么也没做!select没有改变STDOUT
  • 将关闭的文件句柄传递给程序的 STDIN 可能会导致问题。

使固定:

use File::Spec qw( );
use IPC::Open3 qw( open3 );

my $child_stderr;
my $pid = do {
   open(local *CHILD_STDIN,  '<', File::Spec->devnull) or die $!;
   open(local *CHILD_STDOUT, '>', File::Spec->devnull) or die $!;
   $child_stderr = \( local *CHILD_STDERR );
   open3('<&CHILD_STDIN', '>&CHILD_STDOUT', $child_stderr, $cmd)
};
while (<$child_stderr>) { }
waitpid($pid, 0);

笔记:

  1. 我不使用通过 and 机制传递打开open3'<&SYM'文件'>&SYM'句柄。如果你不这样做,至少有一个地方会出现问题。

  2. 有更易于使用的高级模块,例如IPC::Run3IPC::Run

  3. 使用File::Spec->devnull()代替'/dev/null'可能是矫枉过正。你的程序真的可以在其他平台上运行/dev/null吗?

于 2013-12-05T15:15:12.217 回答
2

>&...表达式还可以包含一个数字文件描述符,因此

open my $NULL, '>', ... ;
my $pid = open3(gensym, ">&" . fileno($NULL), \*PH, "cmd");

是词法文件句柄等价于

open NULL, '>', ... ;
my $pid = open3(gensym, ">&NULL", \*PH, "cmd");
于 2013-12-05T16:08:02.477 回答