How to retrieve program output as soon as it printed?
Asked Answered
E

1

2

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?

Extra answered 15/2, 2018 at 21:40 Comment(0)
F
3

The docs are here:

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();
}

enter image description here

Fabozzi answered 15/2, 2018 at 22:52 Comment(2)
Thank you for answer. btw what desktop are you using?Extra
@Extra That was tmux + powerline (I mostly use i3wm as the windowmanager, but it's not visible)Fabozzi

© 2022 - 2024 — McMap. All rights reserved.