我可以从 perl 中的进程捕获 STDOUT 写入事件吗?
Can I capture STDOUT write events from a process in perl?
我需要(想要?)使用 Minion 队列从 Web 应用程序生成一个缓慢的进程。
过程 - GLPK 求解器 - 可以 运行 很长时间但会生成进度输出。
我想在输出发生时捕获它并将其写入某个地方(数据库?日志文件?)以便它可以作为网络应用程序内的状态更新回放给用户。
这可能吗?我不知道(因此没有代码)。
我正在探索 Capture::Tiny - 它的简单性很好,但我不知道它是否可以在写入时跟踪写入事件。
一种基本方法是使用管道打开,您可以在其中 open 一个管道到一个被分叉的进程。然后 child 中的 STDOUT
通过管道传输到 parent 中的文件句柄,或者 parent 通过管道传输到它的 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: $!";
这样 parent 在发出时就接收到 child 的 STDOUT
。†
错误检查还可以做更多的事情,请参阅手册页,close, and $?
in perlvar. Also, install a handler for SIGPIPE
, see perlipc and %SIG
in perlvar。
有些模块可以更轻松地 运行 和管理外部命令,尤其是检查错误。但是,Capture::Tiny and IPC::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 等。例如,使用 >pty>
而不是 >
设置一个 terminal-like 环境,以便 运行 的外部程序可以返回行缓冲并提供更及时的输出。如果对如何管理流程的需求变得更加复杂,那么使用该模块可以更轻松地工作。
感谢 ikegami 的评论,包括演示 @cmd
。
† 为了证明 parent 在发出时接收到 child 的 STDOUT
使用延迟发出输出的命令.例如,使用
而不是上面的 ls -l
my @cmd = (
'perl',
'-le',
'STDOUT->autoflush(1); for (qw( abc def ghi )) { print; sleep 1; }'
);
这个 Perl one-liner 以一秒的间隔打印单词,这就是它们在屏幕上结束的方式。
我需要(想要?)使用 Minion 队列从 Web 应用程序生成一个缓慢的进程。
过程 - GLPK 求解器 - 可以 运行 很长时间但会生成进度输出。
我想在输出发生时捕获它并将其写入某个地方(数据库?日志文件?)以便它可以作为网络应用程序内的状态更新回放给用户。
这可能吗?我不知道(因此没有代码)。
我正在探索 Capture::Tiny - 它的简单性很好,但我不知道它是否可以在写入时跟踪写入事件。
一种基本方法是使用管道打开,您可以在其中 open 一个管道到一个被分叉的进程。然后 child 中的 STDOUT
通过管道传输到 parent 中的文件句柄,或者 parent 通过管道传输到它的 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: $!";
这样 parent 在发出时就接收到 child 的 STDOUT
。†
错误检查还可以做更多的事情,请参阅手册页,close, and $?
in perlvar. Also, install a handler for SIGPIPE
, see perlipc and %SIG
in perlvar。
有些模块可以更轻松地 运行 和管理外部命令,尤其是检查错误。但是,Capture::Tiny and IPC::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 等。例如,使用 >pty>
而不是 >
设置一个 terminal-like 环境,以便 运行 的外部程序可以返回行缓冲并提供更及时的输出。如果对如何管理流程的需求变得更加复杂,那么使用该模块可以更轻松地工作。
感谢 ikegami 的评论,包括演示 @cmd
。
† 为了证明 parent 在发出时接收到 child 的 STDOUT
使用延迟发出输出的命令.例如,使用
ls -l
my @cmd = (
'perl',
'-le',
'STDOUT->autoflush(1); for (qw( abc def ghi )) { print; sleep 1; }'
);
这个 Perl one-liner 以一秒的间隔打印单词,这就是它们在屏幕上结束的方式。