子命令的Golang管道实时输出



我正在尝试通过管道传输命令的输出,但在写入结束之前似乎没有从管道读取数据。最终,我希望它连接到一个 websocket,该 websocket 在执行命令时流式传输命令的状态。问题是,虽然此代码逐行打印消息,但在程序完成执行之前不会打印任何内容。

cmd := exec.Command(MY_SCRIPT_LOCATION, args)
// create a pipe for the output of the script
// TODO pipe stderr too
cmdReader, err := cmd.StdoutPipe()
if err != nil {
    fmt.Fprintln(os.Stderr, "Error creating StdoutPipe for Cmd", err)
    return
}
scanner := bufio.NewScanner(cmdReader)
go func() {
    for scanner.Scan() {
        fmt.Printf("t > %sn", scanner.Text())
    }
}()
err = cmd.Start()
if err != nil {
    fmt.Fprintln(os.Stderr, "Error starting Cmd", err)
    return
}
err = cmd.Wait()
if err != nil {
    fmt.Fprintln(os.Stderr, "Error waiting for Cmd", err)
    return
}

有什么方法可以做类似的事情,让扫描仪在写入管道而不是写入所有内容后逐行读取?该程序运行大约需要 20 秒,并且有源源不断的更新,因此一次将它们全部完成很烦人。

事实证明,问题不在我上面发布的代码中。这按预期工作。问题是正在执行的 C 程序未正确刷新stdout 。以交互方式运行它时,它按预期工作,但是当stdout被管道传输时,直到我调用flush它才真正被写入。在手动将一些 flush 语句添加到 c 程序后,go 代码按预期工作。

F.Y.I

写入管道时逐行阅读,而不是在写入所有内容后?

我发现该软件包对于那些通过谷歌搜索来讨论这个话题的人来说go-pipeline非常有用。

  • github.com/mattn/go-pipeline @ GitHub

以下相当于git log --online | grep first import | wc -l

package sample
import (
    "fmt"
    "log"
    "github.com/mattn/go-pipeline"
)
func ExampleCommandPipeLine() {
    out, err := pipeline.Output(
        []string{"git", "log", "--oneline"},
        []string{"grep", "first import"},
        []string{"wc", "-l"},
    )
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(string(out))
    // Output:
    // 1
}
  • 在线查看其他示例@Go Playground

最新更新