如何强制golang关闭打开的管道

I have to process a long output of a script and find some data. This data most likely will be located at the almost very beginning of the output. After data found I do not need to process output anymore and can quit.

The issue that I cannot stop processing output because exec.Cmd does not have any function to close opened command.

Here are some simplified code (error handling was ommited):

func processOutput(r *bufio.Reader)(){
   for {
      line, _, err := r.ReadLine()
      if some_condition_meet {
         break
      }
      ......
   }
   return
}

func execExternalCommand(){
   cmdToExecute := "......"
   cmd := exec.Command("bash", "-c", cmdToExecute)
   output, _ := cmd.StdoutPipe()

   cmd.Start()
   r := bufio.NewReader(output)
   go processOutput(r)
   cmd.Wait()
   return
}  

What should I do at the end at processOutput function to stop cmd? Maybe there is another way how to solve it.

Thanks

As it stands, you can't do this from processOutput because all it receives is a bufio.Reader. You would need to pass the exec.Cmd to it for it to do anything with the forked process.

To kill the forked process, you can send it a signal, e.g.: cmd.Process.Kill() or cmd.Process.Signal(os.SIGINT). See documentation on exec.Cmd and os.Process.

You could probably use "context" for example:

package main

import (
    "bufio"
    "context"
    "os/exec"
)

func processOutput(r *bufio.Reader, cancel context.WithCancel) {
    for {
        line, _, err := r.ReadLine()
        if some_condition_meet {
            break
        }
    }
    cancel()
    return
}

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()
    cmdToExecute := "......"
    cmd := exec.CommandContext(ctx, "bash", "-c", cmdToExecute)
    output, _ := cmd.StdoutPipe()

    cmd.Start()
    r := bufio.NewReader(output)
    go processOutput(r, cancel)
    cmd.Wait()
    return
}

In case need to end with a timeout this could work (example is taken from here: https://golang.org/src/os/exec/example_test.go)

func ExampleCommandContext() {
    ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
    defer cancel()

    if err := exec.CommandContext(ctx, "sleep", "5").Run(); err != nil {
    // This will fail after 100 milliseconds. The 5 second sleep
    // will be interrupted.
    }
  }

A basic example just using sleep but closing it after 1 second: https://play.golang.org/p/gIXKuf5Oga