在OS/exec.cmd.wait()之后保存Stdout

发布于 2025-01-29 11:58:33 字数 1195 浏览 4 评论 0原文

我正在与OS/EXEC合作,在命令运行时发送输入和接收输出。 我需要在命令完成后存储命令的返回代码,因此我有一个带有err:= cmd.wait()的goroutine,并且我从err中获得任何失败返回代码。 但是,wait()似乎也丢弃了我还需要的剩余stdout。 那么,如何在cmd.wait()之后保留OS/Exec.cmd的剩余stdout?

示例代码,使用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())
}

此打印: 正确3 正确7 完成的 错误

我想要的 : 正确3 正确7 完成的 没错11

我还尝试将CMD.STDOUT设置为字节。Buffer喜欢:

    var buf bytes.Buffer
    cmd.Stdout = &buf
    scanner := bufio.NewScanner(&buf)

但这是不可靠的。除非我随着时间的延迟添加。

I'm working with os/exec, sending input and receiving output as a command runs.
I need to store the command's return code when it finishes, so I have a goroutine with err := cmd.Wait(), and I get any failure return code from the err.
But Wait() seems to throw away the remaining stdout which I need also.
So how do I preserve the remaining stdout of a os/exec.Cmd after Cmd.Wait()?

Example code, using the Unix bc calculator command:

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())
}

This prints:
true 3
true 7
finished
false

I'd like:
true 3
true 7
finished
true 11

I also tried setting cmd.Stdout to a bytes.Buffer like:

    var buf bytes.Buffer
    cmd.Stdout = &buf
    scanner := bufio.NewScanner(&buf)

But that was unreliable. It printed all false unless I added in delays with time.Sleep().

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

动听の歌 2025-02-05 11:58:33

阅读到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() runs
fmt.Println(scanner.Scan(), scanner.Text())
fmt.Println(scanner.Scan(), scanner.Text()) // prints false
cmd.Wait()

选项2:从等待Goroutine阅读:

cmd := exec.Command("sh", "-c", "bc")
stdin, _ := cmd.StdinPipe()
stdout, _ := cmd.StdoutPipe()
scanner := bufio.NewScanner(stdout)
cmd.Start()

var wg sync.WaitGroup
wg.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() runs
wg.Wait()

Call cmd.Wait() after reading to the end of stdout.

Option 1: call cmd.Wait from the main goroutine after scanner.Scan() returns false.

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() runs
fmt.Println(scanner.Scan(), scanner.Text())
fmt.Println(scanner.Scan(), scanner.Text()) // prints false
cmd.Wait()

Option 2: read from the waiting goroutine:

cmd := exec.Command("sh", "-c", "bc")
stdin, _ := cmd.StdinPipe()
stdout, _ := cmd.StdoutPipe()
scanner := bufio.NewScanner(stdout)
cmd.Start()

var wg sync.WaitGroup
wg.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() runs
wg.Wait()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文