简体   繁体   English

使用带有perlcritic的IPC :: Open3

[英]Use IPC::Open3 with perlcritic

I want to supress output in child process and read only stderr. 我想在子进程中压缩输出并只读取stderr。 perlfaq8 advises to do following: 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);

But then perlcritic argues on using bareword file handles . 但随后perlcritic争论使用裸字文件句柄

The only thing i can devise is to select newly opened descriptor to /dev/null instead on STDOUT , like this: 我唯一可以设计的是在STDOUTselect新打开的描述符到/dev/null ,如下所示:

# 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);

But then perlcritic doesn't like using of select . 但是, perlcritic并不喜欢使用select Is there more elegant solution? 有更优雅的解决方案吗?

The minimal change is just to make the use of NULL in open no longer a bareword by changing it to *NULL. 最小的改变就是通过将NULL更改为* NULL来使open中的NULL不再是一个裸字。

It's still usually considered poor form to use handles of this form (Because they are global variables, though you can make them somewhat less global by applying local to them). 使用这种形式的句柄通常被认为是不好的形式(因为它们是全局变量,尽管你可以通过对它们应用local来使它们更不全局化)。 So I would recommend changing it to instead use my variables for all the handles. 因此我建议将其更改为使用我的变量来处理所有句柄。 It also looks like you're throwing away the stdin filehandle, so that too can be passed the null filehandle (note I'm opening it in read-write mode) 它看起来像你丢弃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);
  • Your select doesn't actually do anything! 你的select实际上什么也没做! select doesn't change STDOUT . select不会更改STDOUT
  • Passing a closed file handle to a program's STDIN can cause problems. 将已关闭的文件句柄传递给程序的STDIN会导致问题。

Fix: 固定:

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);

Notes: 笔记:

  1. I don't use pass opened file handles to open3 except via the '<&SYM' and '>&SYM' mechanism. 我不使用通打开的文件句柄open3除了通过'<&SYM''>&SYM'机制。 There's at least one spot where there's an issue if you don't. 如果不这样做,至少有一个地方存在问题。

  2. There are higher-level modules that are easier to use such as IPC::Run3 and IPC::Run . 有更高级别的模块更易于使用,如IPC :: Run3IPC :: Run

  3. Using File::Spec->devnull() instead of '/dev/null' is probably overkill. 使用File::Spec->devnull()而不是'/dev/null'可能File::Spec->devnull()过分。 Will your program actually work on other platforms without /dev/null ? 你的程序是否真的可以在没有/dev/null其他平台上运行?

The >&... expression can also include a numeric file descriptor, so >&...表达式还可以包含数字文件描述符,所以

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

is the lexical filehandle equivalent of 是词法文件句柄的等价物

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM