cgio

How to retrieve real time output with GSubprocess in C?


I have the following C code:

#include <gio/gio.h>

int main(void) {

    GSubprocess *process;
    gchar *output;
    gchar *error;

    process = g_subprocess_new(G_SUBPROCESS_FLAGS_STDOUT_PIPE, NULL, "./for.sh", NULL);

    g_subprocess_communicate_utf8(process, NULL, NULL, &output, &error, NULL);

    g_print("%s", output);
}

and the following bash code:

#!/bin/bash

for i in {1..3}
do
    echo "$i"
    sleep 1
done

The issue I have with this is that the C code will wait until the bash code (or any other code for that matter) finishes to print its output. And what I'd prefer is to have it printed in real time, line by line.

I have found a solution for this in Python but I don't know how to translate it to C. Any pointers will be appreaciated.

The answer in code is this:

#include <gio/gio.h>

int main(void) {

    GSubprocess *process;
    GInputStream *stream;
    char buffer[4];

    process = g_subprocess_new(G_SUBPROCESS_FLAGS_STDOUT_PIPE, NULL, "./for.sh", NULL);

    stream = g_subprocess_get_stdout_pipe(process);

    while(g_input_stream_read(stream, buffer, sizeof(buffer), NULL, NULL))
        g_print("%s", buffer);

    return 0;
}

The funny things is that depending on the value of buffer[], the output is correct or accompanied by junk. If I change buffer[4] to buffer[8] I get junk. If I use buffer[12] then it's correct. Weird.


Solution

  • You need to get the stdout pipe from the GSubprocess using g_subprocess_get_stdout_pipe(), and then read from it using g_input_stream_read() (or some other input stream reading function) in a loop until the subprocess exits.

    You might want to do the same thing with stderr, but in order to do that you’d need to poll both using a GMainLoop, since you can’t block on reading two streams at once.

    Seeing your Python code might allow people to help you with the C translation of it.