前往:如何通过os.exec执行命令时防止管道阻塞?

时间:2020-05-13 20:13:37

标签: go pipe buffer exec

在Go版本1.14.2中,以下是一些示例代码,这些代码说明了产生命令,通过stdin向其馈送数据,然后捕获其stdout和stderr的常用方法。它利用管道,但是如果在过程完成之前stdout或stderr管道的缓冲区已满,这可能导致程序阻塞(在此示例中省略了错误处理)...

func ExecExample(cmd *exec.Cmd, input *[]byte) {
    stdout, err := cmd.StdoutPipe()
    stderr, err := cmd.StderrPipe()
    stdin, err := cmd.StdinPipe()
    err = cmd.Start()
    stdin.Write(*input)
    stdin.Close()
    stdoutBytes, err := ioutil.ReadAll(stdout)
    stderrBytes, err := ioutil.ReadAll(stderr)
    waitErr := cmd.Wait()
}

如何在Go中重组此示例代码,以使stdout和stderr管道永远不会阻塞?

此外,请注意,我正在寻找一种单独捕获stdout和stderr输出的方法。我不希望将它们合并。

谢谢。

2 个答案:

答案 0 :(得分:3)

让exec软件包为您完成工作。

var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
cmd.Stdin = bytes.NewReader(*input)
err := cmd.Run()
stdoutBytes := stdout.Bytes()
stderrBytes := stderr.Bytes()

exec程序包创建并管理将数据泵入子进程或从子进程中抽取数据所需的goroutine。

Run it in the playground

答案 1 :(得分:2)

在goroutine中读取一个(或两个)流:

var stderrBytes []byte
go func() {
  stderrBytes, _ = ioutil.ReadAll(stderr)
}()

err = cmd.Start()
stdoutBytes, err := ioutil.ReadAll(stdout)