Flush output of child process

前端 未结 2 453
萌比男神i
萌比男神i 2021-01-22 12:20

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

2条回答
  •  [愿得一人]
    2021-01-22 13:05

    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.

    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
    

    With >pty> it sets up a pseudo-terminal for STDOUT of the program in @cmd (it's a pipe with >); also see 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.

    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 $$";
    

    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.

    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.

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

提交回复
热议问题