【发布时间】:2021-10-20 17:56:40
【问题描述】:
我正在尝试在 golang 中运行一个命令,将阅读器提供给它的标准输入,返回它的标准输出,然后将它的标准错误转换为错误消息。
我的问题是:我的代码只在管道输入标准输入并返回标准输出时工作得很好。但是,当我也尝试将 stderr 加载到缓冲区中时,如果 stdout 的信息多于 stdin,则该命令将挂起。我已经对此进行了测试,如果标准输出比标准输入大一个字节,它甚至适用。我已经坚持了几个小时,无法在互联网上找到任何解决方案。
以下是相关代码:
var b bytes.Buffer
cmd := exec.Command(convCmd, convArgs...)
stdin, _ := cmd.StdinPipe()
stdout, _ := cmd.StdoutPipe()
cmd.Stderr = &b
go func() {
defer stdin.Close()
io.Copy(stdin, inStream)
}()
err = cmd.Start()
if b.String == "" {
err = nil
} else {
err = errors.New(b.String()
}
return stdout, err
这个问题让我发疯了,我唯一的猜测是该命令正在等待 stdin 等于 stdout 的大小,但它似乎很奇怪,只有当我尝试将 stderr 加载到缓冲区时它才会这样做。
【问题讨论】:
-
我试过 cmd.Wait(),它会导致命令总是挂起。
-
顺便说一句,有问题的命令是 ImageMagick 的转换。 Inkscape 也失败了,但由于某种原因,它可以与 rsvg-convert 一起正常工作。
-
你肯定需要
Wait()让它在这样启动时工作。该程序可能会挂起,因为它在没有更多数据时等待来自标准输入的更多数据。如果 - 而不是启动 goroutine - 你设置cmd.Stdin = inStream然后使用cmd.Run()(或cmd.Wait()在Start()之后)会发生什么?也尽量不要忽略错误 -
经过更多研究后,我发现了这个问题。结果 cmd.Wait() 一直等到 stdin 和 stdout 都完成写入,所以我试图将命令的 stdout 直接通过管道传递到函数的 return 是搞砸了。我的解决方案是从 cmd.Output() 创建一个新的阅读器,然后将其用作返回 io.Reader。经过一些测试,它似乎没有任何性能影响,我觉得有点奇怪。非常感谢您的帮助,我一定会在我的代码中添加适当的错误处理