How to retrieve program output as soon as it print

2019-05-29 05:10发布

问题:

I have a boost::process::child. There are many examples on how to get all its stdout or stderr in a single vector, but in this method you capture all data at once. But how to retrieve lines/characters as soon as they are printed in child process?

回答1:

The docs are here:

  • Synchronous IO

  • Asynchronous IO

Using ipstream

The simplest way:

Live On Coliru

#include <boost/process.hpp>
#include <iostream>

namespace bp = boost::process;

int main() {
    std::vector<std::string> args { 
        "-c", 
        R"--(for a in one two three four; do sleep "$(($RANDOM%2)).$(($RANDOM%10))"; echo "line $a"; done)--" };

    bp::ipstream output;
    bp::child p("/bin/bash", args, bp::std_out > output);

    std::string line;
    while (std::getline(output, line)) {
        std::cout << "Received: '" << line << "'" << std::endl;
    }
}

Prints (e.g.):

At 0.409434s Received: 'line one'
At 0.813645s Received: 'line two'
At 1.2179s Received: 'line three'
At 2.92228s Received: 'line four'

Using async_pipe

This method is much more versatile and lets you do the "hard" cases where deadlock could occur, like when you want to do other things at the same time instead of blocking for input.

#include <boost/process.hpp>
#include <boost/process/async.hpp>
#include <boost/asio.hpp>
#include <iostream>

namespace bp = boost::process;
using boost::asio::mutable_buffer;

void read_loop(bp::async_pipe& p, mutable_buffer buf) {
    p.async_read_some(buf, [&p,buf](std::error_code ec, size_t n) {
        std::cout << "Received " << n << " bytes (" << ec.message() << "): '";
        std::cout.write(boost::asio::buffer_cast<char const*>(buf), n) << "'" << std::endl;
        if (!ec) read_loop(p, buf);
    });
}

int main() {
    boost::asio::io_service svc;

    std::vector<std::string> args { 
        "-c", 
        R"--(for a in one two three four; do sleep "$(($RANDOM%2)).$(($RANDOM%10))"; echo "line $a"; done)--" };

    bp::async_pipe output(svc);
    bp::child p("/bin/bash", args, bp::std_out > output, svc);

    char buf[1024];
    read_loop(output, bp::buffer(buf));

    svc.run();
}