Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Streaming exec.Command StdoutPipe

Tags:

shell

go

I'm trying to stream the Stdout of a shell command to the console, but am having difficulty.

Here's what I currently have:

cmd := exec.Command("sh", "-c", `for number in {0..10}; do echo "$number "; done;`)
pipe, _ := cmd.StdoutPipe()
reader := bufio.NewReader(pipe)
line, err := reader.ReadString('\n')
for err == nil {
    fmt.Println(line)
    line, err = reader.ReadString('\n')
}

I would expect this to print out the numbers 0 through 10, but it seems to hang on line 3 (the first call to ReadString.

I started with cmd.Output() and cmd.CombinedOutput(), but those methods seem to buffer the entire output stream until the command is complete. I need to process the output as it streams, not wait until the command is complete.

I also tried this: continuously reading from exec.Cmd output, but it didn't seem to work and I went away from it because I really want to read lines and not have to manage the buffer manually.

Other things I've looked through:

  • https://groups.google.com/forum/#!topic/golang-nuts/0xK_IHbHPUU
  • https://golang.org/pkg/os/exec/
  • https://golang.org/pkg/bufio/
like image 263
Joe Avatar asked Oct 13 '17 05:10

Joe


1 Answers

You need to start the command:

cmd := exec.Command("sh", "-c", `for number in {0..10}; do echo "$number "; done;`)
pipe, _ := cmd.StdoutPipe()
if err := cmd.Start(); err != nil {
   // handle error
}
reader := bufio.NewReader(pipe)
line, err := reader.ReadString('\n')
for err == nil {
    fmt.Println(line)
    line, err = reader.ReadString('\n')
}

Call Wait after reaching EOF.

The Output and CombinedOutput methods worked for you because these methods call Start internally.

like image 116
Bayta Darell Avatar answered Nov 15 '22 08:11

Bayta Darell