Используйте IPC::Open3 с 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
утверждает использование файловых дескрипторов без слов.
Единственное, что я могу придумать, это 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
не любит использованиеselect
, Есть ли более элегантное решение?
3 ответа
Минимальное изменение - просто сделать использование NULL в open больше не голым словом, изменив его на *NULL.
Обычно все еще считается плохой формой использовать дескрипторы этой формы (поскольку они являются глобальными переменными, хотя вы можете сделать их несколько менее глобальными, применив к ним локальные переменные) Поэтому я бы рекомендовал изменить его, чтобы вместо этого использовать мои переменные для всех дескрипторов. Выглядит так, как будто вы отбрасываете дескриптор файла stdin, так что тоже можно передать нулевой дескриптор файла (обратите внимание, я открываю его в режиме чтения-записи)
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
, - Передача дескриптора закрытого файла в 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);
Заметки:
Я не использую дескрипторы открытых файлов
open3
кроме как через'<&SYM'
а также'>&SYM'
механизм. Есть по крайней мере одно место, где есть проблема, если нет.Существуют модули более высокого уровня, которые проще в использовании, такие как IPC:: Run3 и IPC:: Run.
С помощью
File::Spec->devnull()
вместо'/dev/null'
вероятно, излишним. Будет ли ваша программа работать на других платформах без/dev/null
?
>&...
Выражение также может включать числовой дескриптор файла, поэтому
open my $NULL, '>', ... ;
my $pid = open3(gensym, ">&" . fileno($NULL), \*PH, "cmd");
является лексическим эквивалентом дескриптора файла
open NULL, '>', ... ;
my $pid = open3(gensym, ">&NULL", \*PH, "cmd");