2016-08-16 2 views
1

Моя задача - запустить программу из perl и сохранить поток управления для начальной задачи, а также захватить вывод программы в скалярных переменных. Сценарий должен использовать только модули perl, доступные в базовом пакете perl.Perl-дескриптор файла со скалярной целью и IPC :: Open3

Мой первый подход был

use POSIX; 
use IPC::Open3; 
use strict; 

my ($invar, $outvar, $errvar, $in, $out, $err, $pid, $pidr); 
open($in, "<",\$invar); 
open($out, ">",\$outvar); 
open($err, ">",\$errvar); 
my $cmd = "sleep 5; echo Test; sleep 5; echo Test; sleep 5;"; 
$pid = open3($in, $out, $err, $cmd); 
my $num = 0; 
for($pidr = $pid; $pidr >= 0;) 
{ 
    sleep(1) if ($pidr = waitpid($pid, WNOHANG)) >= 0; 
    print "$num: $outvar" if $outvar; 
    ++$num; 
} 
close($in); 
close($out); 
close($err); 

При запуске ничего не происходит. Вывод запущенной программы не входит в $outvar. Для того, чтобы проверить, если моя основная идея терпит неудачу, я попытался это:

my $outvar = ""; 
my $out; 
open($out, ">", \$outvar); 
print $out "Test\n"; 
print "--1--\n$outvar"; 
print $out "Test2\n"; 
print "--2--\n$outvar"; 

который правильно выводит, как и ожидалось:

--1-- 
Test 
--2-- 
Test 
Test2 

Возникает вопрос: почему выше программа не работает в качестве тестового примера и вывода текста который должен быть в $outvar?

Рабочий раствор является гораздо более сложным (при добавлении все проверки безопасности, оставленные из этого примера):

use POSIX; 
use IPC::Open3; 
use strict; 

my ($invar, $outvar, $errvar, $in, $out, $err, $pid, $pidr); 
open($in, "<",\$invar); 
open($out, ">",\$outvar); 
open($err, ">",\$errvar); 
my $cmd = "sleep 5; echo Test; sleep 5; echo Test; sleep 5;"; 
$pid = open3($in, $out, $err, $cmd); 
my $num = 0; 
for($pidr = $pid; $pidr >= 0;) 
{ 
    sleep(1) if ($pidr = waitpid($pid, WNOHANG)) >= 0; 
    my $obits; vec($obits, fileno($out), 1) = 1; 
    if(select($obits, undef, undef, 0) > 0) 
    { 
    my $buffer; 
    sysread($out, $buffer, 10240); 
    print "$num: $buffer" if $buffer; 
    } 
    ++$num; 
} 
close($in); 
close($out); 
close($err); 

Он правильно печатает (как должен сделать первый и аналогичным образом):

5: Test 
10: Test 

Для примеров я удалил большую часть обработки ошибок и аналогичный код для STDERR.

+1

Кстати, это называется «дескриптором файла» (поскольку он держится на системном ресурсе), а не «обработчиком файлов» (поскольку он ничего не обрабатывает, так как это не код). – ikegami

ответ

1

open($out, ">", \$outvar); не создает дескриптор системного файла. Вы заметите, что fileno($out) - -1. Один процесс не может записывать в чужую память, а тем более манипулировать ее переменными, поэтому вся концепция ошибочна. Использовать IPC::Run3 или IPC::Run; они эффективно реализуют цикл select для вас. open3 слишком низкоуровневый для большинства приложений.


Второй фрагмент кода работает, потому что open3 ведет себя так, как будто $in, $out и $err являются нераскрытые ручки. Вы могли бы также сделать

$in = gensym(); 
$out = gensym(); 
$err = gensym(); 

Но опять же вы должны использовать IPC :: Run3 или IPC :: Run. Ваша ручная версия страдает от некоторых ошибок, включая ту, которая может привести к тупиковой ситуации.

+0

Текст, который вам очень трудно понять, но после прочтения несколько раз стало понятно, что вы имеете в виду.IPC :: Run3 и IPC :: Run не полезны, см. Описание первой задачи, второе предложение. –

+0

Re "* Текст, который очень трудно понять *", если есть что-то, что не ясно, дайте мне знать, и я объясню дальше. Я говорил в простых предложениях, поэтому я не вижу, где проблема. /// Я знаю, что IPC :: Run3 не полезен для вас, но я включил его, потому что вы не единственный читатель этого ответа, и он проще, чем IPC :: Run. IPC :: Run, otoh, соответствует вашим заявленным требованиям. (Используйте 'start' +' pump' + 'finish' вместо' run'.) – ikegami

+0

Я немного изменил ваш текст. Можно напрямую писать переменные в разных процессах. Я также попробовал тестирование потоков: общий для текстовых переменных. В этом случае он не поддерживается. –

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