[英]Use IPC::Open3 with perlcritic
我想在子進程中壓縮輸出並只讀取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
爭論使用裸字文件句柄 。
我唯一可以設計的是在STDOUT
上select
新打開的描述符到/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);
但是, perlcritic
並不喜歡使用select
。 有更優雅的解決方案嗎?
最小的改變就是通過將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);
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);
筆記:
我不使用通打開的文件句柄open3
除了通過'<&SYM'
和'>&SYM'
機制。 如果不這樣做,至少有一個地方存在問題。
有更高級別的模塊更易於使用,如IPC :: Run3和IPC :: Run 。
使用File::Spec->devnull()
而不是'/dev/null'
可能File::Spec->devnull()
過分。 你的程序是否真的可以在沒有/dev/null
其他平台上運行?
>&...
表達式還可以包含數字文件描述符,所以
open my $NULL, '>', ... ;
my $pid = open3(gensym, ">&" . fileno($NULL), \*PH, "cmd");
是詞法文件句柄的等價物
open NULL, '>', ... ;
my $pid = open3(gensym, ">&NULL", \*PH, "cmd");
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.