【问题标题】:Can I capture STDOUT write events from a process in perl?我可以从 perl 的进程中捕获 STDOUT 写入事件吗?
【发布时间】:2019-01-13 01:28:45
【问题描述】:

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

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

我想在输出发生时捕获它并将其写入某个位置(数据库?日志文件?),以便可以将其作为网络应用程序内的状态更新回放给用户。

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

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

【问题讨论】:

  • 如何启动孩子?使用 IPC::Run,您可以提供回调子。使用 IPC::Run,您还可以使用伪 ttys 来欺骗孩子,如果它正常缓冲,则更频繁地刷新其输出。

标签: perl ipc stdout


【解决方案1】:

一个基本的方法是使用管道打开,你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 提供 cmets,包括演示 @cmd


为了证明父母收到孩子的STDOUT,因为它被发出,使用一个发出延迟输出的命令。例如,代替上面的ls -l 使用

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

这个 Perl 单行打印单词间隔一秒,这就是它们在屏幕上结束的方式。

【讨论】:

    猜你喜欢
    • 2020-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-15
    • 2018-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多