在 os/exec.Cmd.Wait() 之后保留标准输出

我正在使用 os/exec,在命令运行时发送输入和接收输出。我需要在命令完成时存储命令的返回码,所以我有一个带有 的 goroutine err := cmd.Wait(),并且我从错误中获取任何失败返回码。但是 Wait() 似乎扔掉了我还需要的剩余标准输出。那么如何在 Cmd.Wait() 之后保留 os/exec.Cmd 的剩余标准输出?


示例代码,使用 Unix bc 计算器命令:


package main


import (

    "fmt"

    "os/exec"

    "bufio"

    "io"

    "time"

)


func main() {

    cmd := exec.Command("sh", "-c", "bc")

    stdin, _ := cmd.StdinPipe()

    stdout, _ := cmd.StdoutPipe()

    scanner := bufio.NewScanner(stdout)

    cmd.Start()


    go func() {

        cmd.Wait()

        fmt.Println("finished")

    }()


    io.WriteString(stdin, "1 + 2\n")

    fmt.Println(scanner.Scan(), scanner.Text())

    io.WriteString(stdin, "3 + 4\n")

    fmt.Println(scanner.Scan(), scanner.Text())

    io.WriteString(stdin, "5 + 6\n")

    io.WriteString(stdin, "quit\n")  // cmd.Wait() runs

    time.Sleep(time.Second)

    // Prints false :(

    fmt.Println(scanner.Scan(), scanner.Text())

}

这打印: true 3 true 7 finished false


我想:真 3 真 7 完成 真 11


我还尝试将 cmd.Stdout 设置为 bytes.Buffer,例如:


    var buf bytes.Buffer

    cmd.Stdout = &buf

    scanner := bufio.NewScanner(&buf)

但那是不可靠的。除非我用 time.Sleep() 添加延迟,否则它打印的都是假的。


HUWWW
浏览 188回答 1
1回答

红颜莎娜

读取到 stdout 末尾后调用 cmd.Wait()。选项 1:在 scanner.Scan() 返回 false 后从主 goroutine 调用 cmd.Wait。cmd := exec.Command("sh", "-c", "bc")stdin, _ := cmd.StdinPipe()stdout, _ := cmd.StdoutPipe()scanner := bufio.NewScanner(stdout)cmd.Start()io.WriteString(stdin, "1 + 2\n")fmt.Println(scanner.Scan(), scanner.Text())io.WriteString(stdin, "3 + 4\n")fmt.Println(scanner.Scan(), scanner.Text())io.WriteString(stdin, "5 + 6\n")io.WriteString(stdin, "quit\n") // cmd.Wait() runsfmt.Println(scanner.Scan(), scanner.Text())fmt.Println(scanner.Scan(), scanner.Text()) // prints falsecmd.Wait()选项 2:从等待的 goroutine 中读取:cmd := exec.Command("sh", "-c", "bc")stdin, _ := cmd.StdinPipe()stdout, _ := cmd.StdoutPipe()scanner := bufio.NewScanner(stdout)cmd.Start()var wg sync.WaitGroupwg.Add(1)go func() {    for scanner.Scan() {        fmt.Println(scanner.Text())    }    cmd.Wait()    defer wg.Done()}()io.WriteString(stdin, "1 + 2\n")io.WriteString(stdin, "3 + 4\n")io.WriteString(stdin, "5 + 6\n")io.WriteString(stdin, "quit\n") // cmd.Wait() runswg.Wait()
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go