我正在尝试执行 shell 命令并压缩它的输出。 问题是我随后需要与需要 Reader 的 API 进行交互。
为此,我尝试了以下(简化代码):
package main
import (
"encoding/hex"
"testing"
"fmt"
"io"
"io/ioutil"
"os/exec"
"compress/gzip"
)
func TestPipe(t *testing.T) {
cmd := exec.Command("echo", "hello_from_echo")
reader, writer := io.Pipe()
gzW := gzip.NewWriter(writer)
cmd.Stdout = gzW
cmd.Start()
go func() {
fmt.Println("Waiting")
cmd.Wait()
fmt.Println("wait done")
// writer.Close()
// gzW.Close()
}()
msg, _ := ioutil.ReadAll( reader )
fmt.Println( hex.EncodeToString( msg ) )
}
问题是 ReadAll 永远挂起。如果我关闭 gzW
,什么都不会改变。但是,如果我关闭 writer
变量,现在程序结束时不会挂起,但输出是:
$ go test -run Pipe
Waiting
wait done
1f8b080000096e8800ff
PASS
但是,无论我回显什么,输出都是一样的。如果我像这样从命令行尝试:echo "hello_from_echo"|压缩 | hexdump
输出完全不同,所以这种方法有问题。
任何线索可能是什么问题?
提前致谢
最佳答案
您以错误的顺序关闭了 gzip 编写器和管道编写器。您需要关闭 gzip.Writer
以刷新所有缓冲区并写入 gzip 页脚,然后您可以关闭 PipeWriter
以解锁 ReadAll
。此外,添加 WaitGroup
可确保您不会在任何关闭调用时被阻止。
cmd := exec.Command("echo", "hello_from_echo and more")
pr, pw := io.Pipe()
gzW := gzip.NewWriter(pw)
cmd.Stdout = gzW
cmd.Start()
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
err := cmd.Wait()
if err != nil {
log.Println(err)
}
gzW.Close()
pw.Close()
}()
buf, err := ioutil.ReadAll(pr)
if err != nil {
t.Fatal(err)
}
wg.Wait()
fmt.Println(hex.EncodeToString(buf))
关于go - 通过 gzip 将命令输出通过管道传输到 Reader,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40312349/