【发布时间】:2016-08-16 19:07:52
【问题描述】:
我的任务是从 perl 启动一个程序,并保持对启动任务的控制流,以及在标量变量中捕获程序的输出。该脚本应仅使用 perl 基础包中提供的 perl 模块。
我的第一个方法是
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 的类似代码。
【问题讨论】:
-
顺便说一下,它被称为“文件句柄”(因为它持有系统资源),而不是“文件处理程序”(因为它不处理任何东西,因为它不是代码)。
标签: perl asynchronous filehandle