在golang中准备好从stdout管道读取

时间:2018-04-03 16:47:29

标签: go stdout stdin

我面临一个奇怪的golang问题。以下代码将澄清:

package main

import (
    "os/exec"
    "io"
    "fmt"
    "os"
)

var (
    pw io.WriteCloser
    pr io.ReadCloser
)

func main() {
    term := exec.Command("/bin/sh")

    // Get stdin writer pipe
    pw, _ = term.StdinPipe()
    pr, _ = term.StdoutPipe()

    term.Start()

    run("cd ~")
    pwd := run("pwd");

    // Do something with pwd output
    ...

    term.Wait()
}

func run(c string) string {
    io.WriteString(pw, fmt.Sprintln(c))

    buf := make([]byte, 32 * 1024)
    pr.Read(buf)
    return string(buf)
}

我想在shell env中运行一些命令并读取它们的输出。写入/运行命令没有问题,但在阅读时似乎存在一些限制:

  • 你不知道命令是否输出任何内容;
  • 没有办法检查stdout是否准备好被读取。

pr.Read(dest)方法将阻止代码流,直到从stdout读取内容为止。如上所述,目标是顺序读取(不使用go例程和/或无限循环)。这意味着如果我们发送cd命令,则永远不会到达func端。

在stdout文件描述符上通过unix.SetNonblock设置非块标志似乎解决了上述问题,但是你不知道它是否准备就绪,并且从“返回的资源暂时不可用”中返回错误.Read致电。

1 个答案:

答案 0 :(得分:0)

正如CeriseLimón所提到的那样,函数应该成为了这里的方式,因为这些交互式脚本练习传统上是以期待的方式完成的。

您可以将parrellel执行包装到库中,它可能仍然看起来像顺序代码,因此这可能会有所帮助:https://github.com/ThomasRooney/gexpect

自述文件:

child, err := gexpect.Spawn("python")
if err != nil { panic(err) }
child.Expect(">>>")
child.SendLine("print 'Hello World'")
child.Interact()
child.Close()