I want to supress output in child process and read only stderr. perlfaq8 advises to do following:
# 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.
The only thing i can devise is to select
newly opened descriptor to /dev/null
instead on STDOUT
, like this:
# 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
.
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.
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). 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)
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
doesn't actually do anything! select
doesn't change STDOUT
.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:
I don't use pass opened file handles to open3
except via the '<&SYM'
and '>&SYM'
mechanism. There's at least one spot where there's an issue if you don't.
There are higher-level modules that are easier to use such as IPC::Run3 and IPC::Run.
Using File::Spec->devnull()
instead of '/dev/null'
is probably overkill. Will your program actually work on other platforms without /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");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With