带有标量目标和IPC::Open3的Perl文件句柄

带有标量目标和IPC::Open3的Perl文件句柄,perl,asynchronous,filehandle,Perl,Asynchronous,Filehandle,我的任务是从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, "&

我的任务是从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);
按预期正确输出:

--1--
Test
--2--
Test
Test2
问题是:为什么上面的程序不能作为测试示例并输出应该在
$outvar
中的文本

工作解决方案要复杂得多(当您添加本例中遗漏的所有安全检查时):

对于示例,我删除了大部分错误处理和类似的STDERR代码。

open($out,“>”,\$outvar)不创建系统文件句柄。您会注意到
fileno($out)
-1
。一个进程不能写入另一个进程的内存,更不用说操纵它的变量了,所以整个概念是有缺陷的。使用或;它们有效地为您实现
select
循环<代码>open3
对于大多数应用程序来说太低级了


第二个代码段之所以有效,是因为
open3
的行为就像
$in
$out
$err
是未打开的句柄一样。你也可以这么做

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

但同样,您应该使用IPC::Run3或IPC::Run。您的手动版本存在一些错误,包括可能导致死锁的错误。

顺便说一句,它被称为“文件句柄”(因为它持有系统资源),而不是“文件句柄”(因为它不处理任何东西,因为它不是代码)。您的文本很难理解,但是在阅读了几遍之后,你的意思就清楚了。IPC::Run3和IPC::Run没有什么用处,请参阅最初的任务描述,第二句。如果有什么不好的地方,请回答“你的文字很难理解”;我不清楚,让我知道,我会进一步解释。我用简单的句子说话,所以我看不出问题出在哪里我知道IPC::Run3对您没有用处,但我将其包括在内,因为您不是这个答案的唯一读者,而且它比IPC::Run更简单。IPC::跑步,otoh,确实能满足你的要求。(使用
开始
+
+
完成
而不是
运行
)我稍微更改了您的文本。可以跨进程直接写入变量。我还尝试了测试线程:为文本变量共享。只有在这种情况下它才不被支持。@Dirk Stöcker,不要用一种根本不被支持的说法来代替解释为什么一种方法不可能的人的答案。我还原了你的编辑。写入系统文件句柄不能直接导致变量在另一个进程中发生更改。我应该在什么时候编辑帖子?:为了澄清帖子的含义(而不改变该含义)-如果您认为声明线程间/线程间数据存储的概念有缺陷,那么可以。我只是觉得你的措辞不好。如果您认为不可能访问其他线程或其他进程内存,那么您似乎还需要学习一些。
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
$in = gensym();
$out = gensym();
$err = gensym();