我可以从perl的进程中捕获STDOUT写事件吗? [英] Can I capture STDOUT write events from a process in perl?

查看:156
本文介绍了我可以从perl的进程中捕获STDOUT写事件吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need (would like?) to spawn a slow process from a web app using a Minion queue.

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

The process - a GLPK solver - can run for a long time but generates progress output.

我想在发生输出时捕获该输出并将其写入到某个位置(数据库?日志文件?),以便可以在Web应用程序内部以状态更新的形式向用户播放该输出.

I'd like to capture that output as it happens and write it to somewhere (database? log file?) so that it can be played back to the user as a status update inside the web app.

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

Is that possible? I have no idea (hence no code).

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

I was exploring Capture::Tiny - the simplicity of it is nice but I can't tell if it can track write events upon writing.

推荐答案

一种基本方法是使用管道打开,您可以在其中打开通向被分叉的进程的管道.然后,将子级的STDOUT传送到父级的文件句柄,或者父级传送到其STDIN.

A basic way is to use pipe open, where you open a pipe to a process that gets forked. Then the STDOUT from the child is piped to the filehandle in the parent, or the parent pipes to its 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权时就可以得到它.

This way the parent receives child's STDOUT right as it is emitted.

您可以使用错误检查做更多的事情,请参见手册页,关闭 $?在Perlvar中.另外,为SIGPIPE安装处理程序,请参见 perlipc

There is a bit more that you can do with error checking, see the man page, close, and $? in perlvar. Also, install a handler for SIGPIPE, see perlipc and %SIG in perlvar.

有些模块可以更轻松地运行外部命令,尤其是检查错误.但是, Capture :: Tiny

There are modules that make it much easier to run external commands and, in particular, check errors. However, Capture::Tiny and IPC::Run3 use files to transfer the external program's streams.

另一方面, IPC :: Run 为您提供了更多控制权,力量.

On the other hand, the IPC::Run gives you far more control and power.

要执行代码" ......从孩子那里读取"使用回调

To have code executed "... each time some data is read from the child" use a callback

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等.如果对如何管理流程的要求变得更加复杂,那么使用模块.

Once you use IPC::Run a whole lot more is possible, including much better error interrogation, setting up pseudo tty for the process, etc. If demands on how to manage the process grow more complex then work will be easier with the module.

感谢 ikegami 提供评论,包括演示@cmd.

Thanks to ikegami for comments, including the demo @cmd.

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

To demonstrate that the parent receives child's STDOUT as it is emitted use a command that emits output with delays. For example, instead of ls -l above use

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

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

This Perl one-liner prints words one second apart, and that is how they wind up on screen.

这篇关于我可以从perl的进程中捕获STDOUT写事件吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆