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

时间:2017-08-28 15:29:44

标签: go pipe

我必须处理脚本的长输出并找到一些数据。这些数据很可能位于输出的几乎一开始。发现数据后,我不再需要处理输出,可以退出。

我无法停止处理输出的问题,因为exec.Cmd没有任何关闭已打开命令的功能。

以下是一些简化的代码(错误处理被忽略):

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
}  

我应该在processOutput函数结束时做什么来停止cmd?也许还有另一种解决方法。

由于

2 个答案:

答案 0 :(得分:3)

目前,您无法从processOutput执行此操作,因为它收到的只是bufio.Reader。您需要将exec.Cmd传递给它,以便它可以对分叉进程执行任何操作。

要终止分叉过程,您可以向其发送信号,例如:cmd.Process.Kill()cmd.Process.Signal(os.SIGINT)。请参阅exec.Cmdos.Process上的文档。

答案 1 :(得分:1)

您可以使用" context"例如:

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
}

如果需要以超时结束,这可能有用(例如从这里取得: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.
    }
  }

仅使用睡眠但在1秒后关闭它的基本示例:https://play.golang.org/p/gIXKuf5Oga