0

I'm trying to catch output of external program. Example:

#include <stdio.h>
#include <unistd.h>
#include <stddef.h>

int main() {

    int i = 0;

    while(i < 10) {
        printf("i = %i\n", i++);
        usleep(2000000);
    }
    return 0;
}

And here is my main.go:

package main

import (
    "bufio"
    "io"
    "log"
    "os/exec"
)

func reecho(closer io.ReadCloser)  {
    reader := bufio.NewReader(closer)

    for {
        s, e := reader.ReadString('\n')
        if e != nil {
            log.Println(e)
            break
        }
        log.Println(s)
    }
}

func main() {
    cmd := exec.Command("./infcount")
    log.Println("starting ", cmd)
    stdout, err := cmd.StdoutPipe()
    stderr, _ := cmd.StderrPipe()

    if err != nil {
        log.Fatal(err)
    }
    if err := cmd.Start(); err != nil {
        log.Fatal(err)
    }

    go reecho(stdout)
    go reecho(stderr)

    if err := cmd.Wait(); err != nil {
        log.Fatal(err)
    }
}

The problem is buffering of stdout. "reecho" get data only when 4096 bytes in stdout buffer or program is exiting(for my short example). Is there way to decrease size of buffer to catch every line of output?

Update: Same binary 'infcount' works fine when ran from shell. It writes every 'i' to the screen.

dtoch
  • 185
  • 1
  • 2
  • 12
  • Possible duplicate of [How to turn off buffering of stdout in C](https://stackoverflow.com/questions/7876660/how-to-turn-off-buffering-of-stdout-in-c) – Peter Dec 18 '18 at 12:10
  • 1
    Your problem is on the C side, not in the Go program. Call [fflush](https://linux.die.net/man/3/fflush) after each print, for instance. – Peter Dec 18 '18 at 12:11
  • Same binary when ran from shell normally writes to console every 'i'. – dtoch Dec 18 '18 at 12:23
  • 1
    TTYs are different. Run `./infcount | cat` and you see the same behaviour as in Go. Assign `os.Stdout` to `cmd.Stdout` and you see the same behaviour as in the terminal (without `cat`). – Peter Dec 18 '18 at 12:27
  • Actually I don't need to write output of 'infcount' to stdout of my util, I need to parse strings produced by 'infcount', so this assignment is not very useful. Is there way to change tty setting without secondary program modification? – dtoch Dec 18 '18 at 12:49

1 Answers1

0

version of your C program that will track the output as it happens

   #include <stdio.h>
    #include <unistd.h>
    #include <stddef.h>

    int main() {

        int i = 0;

        while(i < 10) {
            printf("i = %i\n", i++);
            usleep(2000000);
            fflush(stdout);
        }
        return 0;
    }

If it is an existing precompiled program then stdbuf may be able to fix it, see https://www.perkin.org.uk/posts/how-to-fix-stdio-buffering.html

Vorsprung
  • 32,923
  • 5
  • 39
  • 63
  • stdbuf is what I'm looking for. Thanks! No another 'go-way' resolve? – dtoch Dec 19 '18 at 14:38
  • As the article linked above explains, the problem is with the flushing behaviour in the external program. stdbuf modifies the libraries that the external program uses. – Vorsprung Dec 20 '18 at 07:24