Golang管道输出子命令实时

时间:2015-06-18 19:29:45

标签: go

我正在尝试管道命令的输出,但是在写入结束关闭之前似乎没有数据从管道中读取。最终我希望它连接到一个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 > %s\n", 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秒,并且有一个稳定的更新流,因此让它们全部通过是很烦人的。

2 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:0)

F.Y.I

<块引用>

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

我发现 go-pipeline 包对那些通过谷歌搜索了解这个主题的人非常有用。

下面等价于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
}