读者从未读过“ StdoutPipe”

时间:2019-05-04 22:52:24

标签: go

我正试图从一个长期运行的(阻塞/类似shell的)命令中读取stdout,最终目的是创建一个Go可以与之交互的sidecar进程。

我有以下MCVE:

func main() {
    var err error
    // Build the long-running command
    args := []string{"-i0", "-o0", "-e0", "/usr/local/bin/ipython"}
    cmd := exec.Command("stdbuf", args...)

    // Keep the stdin file descriptor open
    // Spawned command should block waiting for input
    _, err = cmd.StdinPipe()
    if err != nil {
        panic(err)
    }

    // Setup pipe of `Reader` type
    var stdoutBuf []byte
    stdout, err := cmd.StdoutPipe()
    if err != nil {
        panic(err)
    }

    // Start the command
    if err = cmd.Start(); err != nil {
        panic(err)
    }

    go func() {
        for {
            // Asynchronously continue reading from stdout
            n, err := stdout.Read(stdoutBuf)
            fmt.Println(n)
            if err != nil {
                panic(err)
            }
            fmt.Println(stdoutBuf)
            time.Sleep(time.Millisecond * 2000)
        }
    }()

    // Block forever
    if err = cmd.Wait(); err != nil {
        panic(err)
    }
}

从理论上讲,这种方法似乎可行。我希望stdout.Read会返回一些内容(ipython shell序言),但是n始终为0。

  1. 在这个例子中,Reader.Read为什么从不读取任何内容?
  2. 一些相关的问题:如果没有什么可阅读的,我有什么办法可以阻止阅读StdoutPipe

我认为该进程本身没有任何问题(这将导致读取无效的文件描述符),因为Start不会panic,并且似乎cmd.Wait会永远阻塞

1 个答案:

答案 0 :(得分:1)

  

在这个示例中,Reader.Read为什么从不读取任何内容?

因为您正在读取大小var stdoutBuf []byte创建的大小为0的缓冲区。而是使用类似以下内容的

stdoutBuf := make([]byte, 4096)

您可能还想使用bufio

  

一些相关的问题:如果没有什么可阅读的,我有什么办法可以阻止阅读StdoutPipe

stdout.Read已经被阻止,这是io.Reader的典型特征(尽管不是必需的):

  

如果一些数据可用,但不是len(p)个字节,按常规方式,Read将返回可用数据,而不是等待更多数据。 [...]除了len(p)== 0时,不建议返回零字节计数且没有错误