Go语言 即使我关闭了Stdout和Stderr管道,

qmb5sa22  于 12个月前  发布在  Go
关注(0)|答案(1)|浏览(104)

我正在尝试实时异步读取Stdout和Stderr。
这是有效的,但它在执行后永远挂起。我正在关闭管道,所以我不确定它在等待什么:

stdOutP, stdOutW := io.Pipe()
stdErrP, stdErrW := io.Pipe()

cmd := exec.Command("ping", "google.com", "-c", "10")

cmd.Stdout = io.MultiWriter(os.Stdout, stdOutW)
cmd.Stderr = io.MultiWriter(os.Stderr, stdErrW)

stdOutScanner := bufio.NewScanner(stdOutP)
stdErrScanner := bufio.NewScanner(stdErrP)

stdOutDone := make(chan bool)
go func() {
    defer stdOutP.Close()

    for stdOutScanner.Scan() {
        // Do something with output...
        fmt.Println("From stdOut buffer: " + stdOutScanner.Text())
    }
    stdOutDone <- true
}()

stdErrDone := make(chan bool)
go func() {
    defer stdErrP.Close()

    for stdErrScanner.Scan() {
        // Do something with output...
        fmt.Println("From stdErr buffer: " + stdErrScanner.Text())
    }
    stdErrDone <- true
}()

err := cmd.Start()
<-stdOutDone
<-stdErrDone

err = cmd.Wait()
if err != nil {
    fmt.Printf(err.Error())
}

字符串
我甚至尝试在cmd.Wait()调用之前和之后关闭通道

close(stdOutDone)
close(stdErrDone)

编辑

我得到了我的答案。
封闭式的writer not reader:

defer stdOutW.Close()
defer stdErrW.Close()


然后在运行Start()之前关闭通道-这让我很困惑。通道什么时候关闭?我希望什么都不会发生,因为我在启动命令之前关闭它们!

close(stdOutDone)
close(stdErrDone)

err := cmd.Start()

v09wglhw

v09wglhw1#

要中断扫描循环并退出goroutines,请在命令退出后关闭管道的写入端。额外的好处:使用sync.WaitGroup等待goroutines完成。

stdOutP, stdOutW := io.Pipe()
stdErrP, stdErrW := io.Pipe()

cmd := exec.Command("ping", "google.com", "-c", "10")

cmd.Stdout = io.MultiWriter(os.Stdout, stdOutW)
cmd.Stderr = io.MultiWriter(os.Stderr, stdErrW)

stdOutScanner := bufio.NewScanner(stdOutP)
stdErrScanner := bufio.NewScanner(stdErrP)

var wg sync.WaitGroup
wg.Add(1)
go func() {
    defer wg.Done()
    for stdOutScanner.Scan() {
        // Do something with output...
        fmt.Println("From stdOut buffer: " + stdOutScanner.Text())
    }
}()

wg.Add(1)
go func() {
    defer wg.Done()
    for stdErrScanner.Scan() {
        // Do something with output...
        fmt.Println("From stdErr buffer: " + stdErrScanner.Text())
    }
}()

err := cmd.Run()
if err != nil {
    log.Fatal(err)
}
stdOutW.Close()
stdErrW.Close()
wg.Wait()

字符串
https://go.dev/play/p/uUib9AiDCft

相关问题