如何从调用它的perl程序中查看正在运行的程序的标准输出?

如何从调用它的perl程序中查看正在运行的程序的标准输出?,perl,file-io,io,exec,parent-child,Perl,File Io,Io,Exec,Parent Child,我们试图找出如何在perl脚本中运行java应用程序,但仍然能够定期读取java应用程序的标准输出 print "running dcmrcv.bat\n"; open my $fh_dcmrcv, "-|", 'z:\apps\dcm4che\dcm4che-2.0.26\bin\dcmrcv.bat \ DCMRCV:11112 -dest z:\dcmrcv -journal z:\dcmrcv', or die "could not execute dcmrcv: $!";

我们试图找出如何在perl脚本中运行java应用程序,但仍然能够定期读取java应用程序的标准输出

print "running dcmrcv.bat\n";

open my $fh_dcmrcv, "-|", 'z:\apps\dcm4che\dcm4che-2.0.26\bin\dcmrcv.bat \
  DCMRCV:11112 -dest z:\dcmrcv -journal z:\dcmrcv', 
  or die "could not execute dcmrcv: $!";

print "dcmrcv.bat started\n";
我们希望能够每隔几分钟从文件句柄读取$fh_dmcrcv,或者在文件句柄上有活动时设置AnyEvent io触发器

但是,当我尝试从filehandle读取时,如果我使用以下内容,它将被阻止:

foreach my $line (<$fh_dmcrcv>) {
  print $line;
}
Z:\projects\demo_2>process_files.pl
running dcmrcv.bat
dcmrcv.bat started
Start Server listening on port 11112
11:55:13,495 INFO   - Start listening on 0.0.0.0/0.0.0.0:11112
脚本process_files.pl正在发出msgs:

running dcmrcv.bat
dcmrcv.bat started
MSG。从java程序中可以看到: 在端口11112上启动服务器侦听 11:55:13495信息-从0.0.0.0/0.0.0.0:11112开始收听

在本例中,我们只是为了这个问题而重复这些内容,实际上我们想要周期性地解析某些MSG。永远不要重复任何一个

任何见解都值得赞赏


-Sam

试着用这个来阅读:

while (my $line = <$fh_dmcrcv>) {
   print $line;
}
关于

当读取不会阻塞时,使用或四参数选择读取。编辑:没关系,你是,所以这行不通。一个选项是:让一个中间进程从这个管道中读取,并让一个中间文件填充您所需要的任何尾部长度。呜呜


也就是说,每隔几分钟从管道中读取数据的最佳方法是每隔几秒钟从管道中读取数据。

大多数系统都支持一个4参数选择函数,该函数也可以很好地打包,可以告诉您是否有输入等待sockethandle或pipehandle。在Windows中,select仅在套接字上受支持,这导致了这种拜占庭式解决方案:

创建套接字对 Fork并在子进程中运行该命令 在子进程中,检索命令输出并将其写入套接字 在父级中,根据需要对套接字使用选择和读取操作 例如:

use Socket;
use IO::Select;
use Time::HiRes;
$cmd = $^X . ' -MMath::BigInt -e "$_=1; '
       . 'print qq/$_!=/,Math::BigInt->new($_)->bfac(),qq/\n\n\n/'
       . ' for 4000..4100"';
socketpair A,B,AF_UNIX,SOCK_STREAM,PF_UNSPEC;  # step 1
if (fork() == 0) {
    open my $fh, '-|', $cmd;                   # step 2
    while (<$fh>) {
        print B;                               # step 3
    }
    close $fh;
    exit $? >> 8;
}
$s = IO::Select->new();
$s->add(\*A);
for (;;) {
    if ($s->can_read(0.25)) {                  # step 4
        $line = <A>;
        print "Do something with command output: $line";
    } else {
        print "No output now. Could be doing something else ...\n";
        Time::HiRes::sleep(0.25);
    }
}

是否确实不想只将命令输出写入临时文件?

能否将应用程序输出写入临时文件,然后使用file::Tail?我们正在尝试避免这种方法。我们不想因为必须旋转或修剪文件而不得不管理此文件。您是否尝试使用fctrl将描述符设置为O_NONBLOCK?当您说它通常是块时,您到底观察到了什么行为?@TLP尝试了这一结果的变化。从文件句柄读取会阻塞perl程序。你说得对。您可能需要检查您的系统是否支持使用非阻塞选项打开文件,以便在文件描述符中没有任何内容可读取时,读取不会锁定。每隔几秒钟,您可能会在perl的sysopenread中发现一些提示—如果您的命令生成大量输出,则尤其如此。管道和套接字上的默认缓冲区大小可能非常小,当命令在管道上没有更多空间写入时,该命令将被阻塞。这90%有效。我需要在打印B之后添加一个B->flush,以便让套接字的缓冲区刷新所有挂起的输出。接受这一点让我很痛苦,因为必须通过套接字模块使用隧道IO是一种彻底的黑客行为,但除此之外,我还无法想出任何其他可行的方法。恭喜你,这是我能找到的最好的答案。