2015-03-16 2 views
0

Я использую IPC::Open3 за предложение, данное Hans Lub here.Предупреждение в IPC :: Open3 при использовании open3 дважды

Моя проблема заключается в том, что open3 вызов работает правильно в первый раз, но последующие вызовы возвращают предупреждение:

Use of uninitialized value in numeric ne (!=) at /usr/lib/perl5/5.8.8/IPC/Open3.pm line 215. 

Пример кода я использую выглядит следующим образом:

use IPC::Open3; 

my $pid; 
# dup the old standard output and error 
open(OLDOUT, ">&STDOUT") or die "Can't dup STDOUT: $!\n"; 
open(OLDERR, ">&STDERR") or die "Can't dup STDERR: $!\n"; 

my $transcript_file = "transcript.temp"; 
# reopen stdout and stderr 
open (STDOUT, "|tee -i $transcript_file") or die "Can't reopen STDOUT: $!\n"; 
open (STDERR, ">&STDOUT")    or die "Can't reopen STDERR: $!\n"; 

# print statements now write to log 
print "Logging important info: blah!\n"; 
print STDERR "OOPS!\n"; 

#eval { $pid = open3("\*STDIN", "\*OLDOUT", "\*OLDERR", "ls"); }; # Tried this, but doesnt seem to help. Output does not appear on STDOUT. 
eval { $pid = open3(">&STDIN", ">&OLDOUT", ">&OLDERR", "ls"); }; #This works correctly 
waitpid($pid, 0); 

eval { $pid = open3(">&STDIN", ">&OLDOUT", ">&OLDERR", "ls"); }; #First warning 
waitpid($pid, 0); 

eval { $pid = open3(">&STDIN", ">&OLDOUT", ">&OLDERR", "ls"); }; #Second warning 
waitpid($pid, 0); 

I извиниться, если я пытаюсь заставить других решить мои проблемы, но я просто не могу обойти это, и просмотр модулей Perl выходит за рамки моего нынешнего понимания.

+0

Предлагаю начать с обновления модуля 'IPC :: Open3'. В текущей версии строка 215 является пустой строкой. – Borodin

+0

Попробуйте 'open3 (\ * STDIN, \ * OLDOUT, \ * OLDERR)'. – nwellnhof

+0

К сожалению, обновление модуля выходит за рамки моей сферы влияния. Я вынужден использовать то, что доступно: Perl версии 5.8.8 и Open3 V1.1. – Abhishek

ответ

2

Не имеет смысла передавать один и тот же STDIN в несколько параллельных процессов. open3 таким образом предполагает, что дескриптор, который вы указываете open3, не используется ничем другим, поэтому он закрывает его.

Похоже, что ваши дети не используют STDIN, который вы им предоставляете, поэтому вы должны предоставить ручку /dev/null.

open(local *CHILD_STDIN, '<', '/dev/null') or die $!; 
$pid = open3('<&CHILD_STDIN', '>&STDOUT', '>&STDERR', @cmd); 
+0

Спасибо. Это работает как шарм. – Abhishek

1

Я думаю, что проблема заключается в том, как open3 использует обработанные вами файлы. Если вы используете, скажем, >&STDOUT, тогда дескриптор файла обманут, обманутый передается дочернему процессу, а копия родителя - закрыта. Это означает, что во второй раз, когда вы делаете то же самое, вы дублируете дескриптор закрытого файла, который не имеет нужного эффекта.

Единственный способ, с помощью которого я могу видеть, - обмануть файлы вручную отдельно и передать обманы дочернему процессу. Не имеет значения, что копия обложек родителя закрыта, поскольку у нее все еще есть оригинал STDOUT и т. Д. К сожалению, он добавляет еще три оператора к каждому вызову open3, поэтому вы, вероятно, захотите обернуть все это в подпрограмму, например ,

my_open3('ls'); 
my_open3('ls'); 
my_open3('ls'); 

sub my_open3 { 

    my @cmd = @_; 
    my $pid; 

    open IN_COPY, '<&', STDIN or die "Couldn't dup STDIN: $!"; 
    open OUT_COPY, '>&', STDOUT or die "Couldn't dup STDOUT: $!"; 
    open ERR_COPY, '>&', STDERR or die "Couldn't dup STDERR: $!"; 

    eval { 
    $pid = open3('>&IN_COPY', '>&OUT_COPY', '>&ERR_COPY', @cmd); 
    }; 

    waitpid $pid, 0; 
} 

Это не самый хороший решений, так что если кто может увидеть что-нибудь лучше, пожалуйста перезвон в. Единственной альтернативой я могу видеть это позволить родительским держать свой собственный стандарт IO обрабатывает и использовать совершенно новые для связи с дочерним процессом каждый раз. Затем родительский интерфейс будет беспорядочен с IO::Select, чтобы выполнить копирование с дочернего вывода на свои STDOUT и STDERR.

Как nwellnhof говорит, если ребенок не использует его STDIN (как в случае с командой ls), то вы можете просто передать undef в качестве первого параметра. Это экономит дублирование одной из трех стандартных ручек.

+0

Первый вызов 'open3' будет использовать все входные данные на * stdin * в любом случае. Поэтому для последующих вызовов 'open3' вы можете просто передать' undef' в качестве первого аргумента. (Или передайте 'undef' все время, если вызываемая программа не читает из * stdin *.) – nwellnhof

+0

@nwellnhof: Спасибо. Я добавил заметку о своем решении. – Borodin

+0

Спасибо вам обоим. Это помогло. Экспериментирование далее показало, что дубление STDOUT и STDERR не требуется (не знаю, почему, поскольку это должно быть логически). Поскольку не было необходимости в STDIN, который я использовал раньше, передача undef заставляет ошибку уйти. – Abhishek

Смежные вопросы