我尝试执行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" | gzip | hexdump
输出完全不同,所以这种方法有问题。
有任何疑问可能是什么问题?
提前致谢
答案 0 :(得分:2)
您正在以错误的顺序关闭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))