我想在子进程中压缩输出并只读取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
在using bareword file handles争论。
我唯一可以设计的是select
新打开的描述符到/dev/null
而不是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
不喜欢using of select
。
有更优雅的解决方案吗?
答案 0 :(得分:3)
最小的改变就是通过将NULL更改为* NULL来使open中的NULL不再是一个裸字。
使用这种形式的句柄通常仍然被认为是糟糕的形式(因为它们是全局变量,尽管你可以通过对它们应用local来使它们在某种程度上不那么全局化)。因此我建议将其更改为使用我的变量来处理所有句柄。它看起来像你丢弃stdin文件句柄,所以也可以传递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);
答案 1 :(得分:3)
select
实际上什么也没做! select
不会更改STDOUT
。修正:
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);
注意:
答案 2 :(得分:2)
>&...
表达式还可以包含数字文件描述符,所以
open my $NULL, '>', ... ;
my $pid = open3(gensym, ">&" . fileno($NULL), \*PH, "cmd");
是等同于
的词法文件句柄open NULL, '>', ... ;
my $pid = open3(gensym, ">&NULL", \*PH, "cmd");