3

I use the following code which works, The problem is that the output is printed just as the process finished to execute, I want to print to the screen the output live and not provide all the output when the process finishes, how can I achieve this?

cmdParams := [][]string{
    {filepath.Join(dir,path), "npm", "install"},
    {filepath.Join(pdir,n.path), "gulp"},
}

for _, cp := range cmdParams {
    log.Printf("Starting %s in folder %s...", cp[1:], cp[0])
    cmd := exec.Command(cp[1], cp[2:]...)
    cmd.Dir = cp[0]
    // Wait to finish, get output:
    out, err := cmd.Output()
    if err != nil {
        log.Printf("Error running %s: %v\n", cp[1:], err)
        return
    }
    log.Println("Finished %s, output: %s", cp[1:], out)
}

update when trying the proposed solution I got the output like

2018/02/18 11:11:57  Starting [npm install] in folder ...
2018/02/18 11:12:14 adde
2018/02/18 11:12:14 d 56
2018/02/18 11:12:14 3 pa
2018/02/18 11:12:14 ckag
2018/02/18 11:12:14 es i
2018/02/18 11:12:14 n 15
2018/02/18 11:12:14 .477
2018/02/18 11:12:14 s
2018/02/18 11:12:14 Finished %s [npm install]
6
  • Possible duplicate of Streaming commands output progress. Also see related: How to get the realtime output for a shell command in golang? Commented Feb 18, 2018 at 8:03
  • @icza - so I should use oneByte := make([]byte, 1) for { _, err := stdout.Read(oneByte) if err != nil { break } fmt.Printf("%c", oneByte[0]) } for this case ? if so where ? it's a bit confusing ... Commented Feb 18, 2018 at 8:13
  • Use the solution from the accepted answer of the suggested duplicate. Commented Feb 18, 2018 at 8:19
  • @icza - do you mean -scanner := bufio.NewScanner(stdout) scanner.Split(bufio.ScanRunes) ? Commented Feb 18, 2018 at 8:20
  • @icza - it will be great if you can provide example with my context, since I read the post and it's difference , I run several command and I use the cmd.Output() which I dont understand how to relate them... Commented Feb 18, 2018 at 8:22

1 Answer 1

3

Using the solution presented in this answer: Streaming commands output progress

cmdParams := [][]string{
    {filepath.Join(dir, path), "npm", "install"},
    {filepath.Join(pdir, n.path), "gulp"},
}
for _, cp := range cmdParams {
    log.Printf("Starting %s in folder %s...", cp[1:], cp[0])
    cmd := exec.Command(cp[1], cp[2:]...)
    cmd.Dir = cp[0]

    stdout, err := cmd.StdoutPipe()
    if err != nil {
        log.Printf("%s cmd.StdoutPipe() error: %v\n", cp[1:], err)
        return
    }
    // Start command:
    if err = cmd.Start(); err != nil {
        log.Printf("%s start error: %v\n", cp[1:], err)
        return
    }

    // Stream command output:
    scanner := bufio.NewScanner(stdout)
    scanner.Split(bufio.ScanRunes)
    for scanner.Scan() {
        fmt.Print(scanner.Text())
    }
    if scanner.Err() != nil {
        log.Printf("Reading %s stdout error: %v\n", cp[1:], err)
        return
    }

    // Get execution success or failure:
    if err = cmd.Wait(); err != nil {
        log.Printf("Error running %s: %v\n", cp[1:], err)
        return
    }
    log.Printf("Finished %s", cp[1:])
}

Some explanation:

This line:

scanner := bufio.NewScanner(stdout)

Creates a bufio.Scanner that will read from the pipe that supplies the output written by the process.

This line:

scanner.Split(bufio.ScanRunes)

Instructs the scanner to read the input by runes instead of the default by-lines.

Note that the above example only streams the standard output of the process. If you also need its standard error stream, you could also read from Command.StderrPipe().

Also note that this won't work with some commands that don't write everything to their standard output or error. For details, see How to get the realtime output for a shell command in golang?

Sign up to request clarification or add additional context in comments.

14 Comments

Thanks 1+ , can you see my updates why the output is like this ?
I think it's becouse of count, err := stdout.Read(oneRune) , any idea how to overcome this?
Thanks, I've tried it and now I got even worse 2018/02/18 11:44:14 a 2018/02/18 11:44:14 d 2018/02/18 11:44:14 d 2018/02/18 11:44:14 e 2018/02/18 11:44:14 d 2018/02/18 11:44:14 2018/02/18 11:44:14 5
each byte in a new line
@RaynD Do note when streaming the output I use fmt.Printf() and not log.Printf().
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.