我可以从perl的进程中捕获STDOUT写入事件吗?

时间:2018-08-06 06:26:24

标签: perl

我需要(想要吗?)使用Minion队列从Web应用程序中生成缓慢的进程。

该过程-GLPK求解器-可以运行很长时间,但会生成进度输出。

我想捕获该输出,并将其写入到某个地方(数据库?日志文件?),以便可以在Web应用程序中以状态更新的形式向用户播放该输出。

有可能吗?我不知道(因此也没有代码)。

我正在探索Capture::Tiny-它的简单性很好,但是我无法确定它是否可以在写入时跟踪写入事件。

1 个答案:

答案 0 :(得分:4)

一种基本方法是使用管道打开,在该管道上open将管道连接到派生的进程。然后,将子级的STDOUT输送到父级中的文件句柄,或父级输送到其STDIN中。

use warnings;
use strict;

my @cmd = qw(ls -l .);  # your command

my $pid = open(my $fh, '-|', @cmd)   // die "Can't open pipe from @cmd: $!";

while (<$fh>) {
    print;
}

close $fh or die "Error closing pipe from @cmd: $!";

通过这种方式,父母在孩子发出STDOUT的权利时就可以得到它。

您可以使用错误检查做更多的事情,请参见手册页close$? in perlvar。另外,为SIGPIPE安装处理程序,请参见perlipc%SIG in perlvar

有些模块可以更轻松地运行外部命令,尤其是检查错误。但是,Capture::TinyIPC::Run3使用文件来传输外部程序的流。

另一方面,IPC::Run为您提供了更多的控制和功能。

"... each time some data is read from the child"执行代码,请使用回调

use warnings;
use strict;

use IPC::Run qw(run);

my @cmd = ( 
    'perl', 
    '-le', 
    'STDOUT->autoflush(1); for (qw( abc def ghi )) { print; sleep 1; }'
);

run \@cmd, '>', sub { print $_[0] };

一旦您使用IPC::Run,则可能会做更多的事情,包括更好的错误查询,为流程设置伪tty等。如果对如何管理流程的要求变得更加复杂,则工作将变得更加容易与模块。

感谢ikegami的评论,包括演示@cmd


要演示父级在发出子级STDOUT时收到它,请使用命令来延迟输出。例如,代替上面的ls -l使用

my @cmd = (
    'perl', 
    '-le', 
    'STDOUT->autoflush(1); for (qw( abc def ghi )) { print; sleep 1; }'
);

这种Perl单线打印的单词相隔一秒,这就是它们在屏幕上的显示方式。