刷新子进程的输出 [英] Flush output of child process

查看:93
本文介绍了刷新子进程的输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我通过IPC::Open2创建了一个子进程.
我需要逐行从此子进程的标准输出中读取.
问题是,由于子进程的stdout未连接到终端,因此已完全缓冲,在进程终止之前我无法从中读取信息.

I created a child process via IPC::Open2.
I need to read from the stdout of this child process line by line.
Problem is, as the stdout of the child process is not connected to a terminal, it's fully buffered and I can't read from it until the process terminates.

如何在不修改其代码的情况下刷新子进程的输出?

子进程代码

while (<STDIN>) {
    print "Received : $_";
}

父流程代码:

use IPC::Open2;
use Symbol;

my $in = gensym();
my $out = gensym();

my $pid = open2($out, $in, './child_process');

while (<STDIN>) {
    print $in $_;
    my $line = <$out>;
    print "child said : $line";
}


当我运行代码时,在等待子进程的输出时卡住了.
但是,如果我用bc运行它,结果是我期望的,我相信bc必须手动刷新其输出


When I run the code, it get stucks waiting the output of the child process.
However, if I run it with bc the result is what I expect, I believe bc must manually flush its output

注意:
在子进程中,如果我在开始时添加$| = 1或在打印后添加STDOUT->flush(),则父进程可以从中正确读取.
但这是一个示例,我必须处理不手动刷新其输出的程序.

note:
In the child process if I add $| = 1 at the beginning or STDOUT->flush() after printing, the parent process can properly read from it.
However this is an example and I must handle programs that don't manually flush their output.

推荐答案

一种方法是为进程设置类似于终端的环境,即伪终端(pty).这很难做到,并且非常依赖系统,但是 IPC :: Run 具有功能易于使用.

One way is to set up a terminal-like environment for the process, a pseudo-terminal (pty). That is hard to do right and is very system dependent, but IPC::Run has that capability ready for easy use.

这里是驱动程序,使用at工具运行,使其没有控制终端(或通过cron运行)

Here is the driver, run using at facility so that it has no controlling terminal (or run it via cron)

use warnings;
use strict;
use feature 'say';

use IPC::Run qw(run);

my @cmd = qw(./t_term.pl input arguments); 

run \@cmd, '>pty>', sub { say "out: @_" };

#run \@cmd, '>', sub { say "out: @_" }   # no pty

使用>pty>可以为@cmd中的程序的STDOUT设置伪终端(这是带有>的管道);另请参见<pty<和更多有关重定向的 . 每当孩子的输出时,都会调用匿名sub {},因此人们可以随时处理它.还有其他选择.

With >pty> it sets up a pseudo-terminal for STDOUT of the program in @cmd (it's a pipe with >); also see <pty< and see more about redirection. The anonymous sub {} gets called every time there is output from the child, so one can process it as it goes. There are other options for this as well.

名为(t_term.pl)的程序仅测试终端

The program that is called (t_term.pl) only tests for a terminal

use warnings;
use strict;
use feature 'say';

say "Is STDOUT filehandle attached to a terminal: ",
    ( (-t STDOUT) ? "yes" : "no" );
sleep 2;
say "bye from $$";

-t STDOUT(请参阅文件测试操作符)是一种适合的方法在此示例中检查端子.有关更多/其他方式,请参见这篇文章.

The -t STDOUT (see filetest operators) is a suitable way to check for a terminal in this example. For more/other ways see this post.

输出显示被调用程序(t_term.pl)确实在其STDOUT上看到一个终端,即使驱动程序没有驱动程序运行(使用at或用尽crontab).如果使用>(使用管道)将>pty>更改为常规重定向,则没有端子.

The output shows that the called program (t_term.pl) does see a terminal on its STDOUT, even when a driver runs without one (using at, or when run out of a crontab). If the >pty> is changed to the usual redirection with > (using a pipe) then there is no terminal.

这是否能解决缓冲问题,显然取决于该程序,以及是否足以将其与终端欺骗.

Whether this solves the buffering problems is clearly up to that program, and whether it is enough to fool it with a terminal.

解决问题的另一种方法是,尽可能使用unbuffer,如暴民的回答.

Another way around the problem is using unbuffer when possible, as in mob's answer.

这篇关于刷新子进程的输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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