如何将可执行二进制文件的输出写入内存而不是磁盘



我得到了一个二进制文件,其工作原理如下:

> ./my_bin raw.avi output_file.avi

output_file.avi是我想要的,当作业成功时,一些详细的信息会打印在终端中,比如:

版权所有2022 Company股份有限公司…成功。

我想在代码中运行这个命令,并将output_file.avi重定向到某个字节数组中,这样我就不必从磁盘中读取并删除它

func wrongOne(stdin []byte) ([]byte, error) {
inBuf := bytes.NewBuffer(stdin)
outBuf := bytes.NewBuffer(nil)
cmd := exec.Command("./my_bin", "/dev/stdin", "/dev/stdout")
cmd.Stdin = inBuf
cmd.Stdout = outBuf
err := cmd.Run()
if err != nil {
return nil, err
}
return outBuf.Bytes(), nil // wrong
}

但是,返回字节数组比下面的方法更长,这导致MD5检查失败。

func correctOne(stdin []byte) ([]byte, error) {
inBuf := bytes.NewBuffer(stdin)
cmd := exec.Command("./my_bin", "/dev/stdin", "output_file")
cmd.Stdin = inBuf
err := cmd.Run()
if err != nil {
return nil, err
}
return os.ReadFile("output_file")
}

wrongOne函数可以修改为正确的以下代码:

func modifiedWrongOne(stdin []byte) ([]byte, error) {
inBuf := bytes.NewBuffer(stdin)
outBuf := bytes.NewBuffer(nil)
cmd := exec.Command("./my_bin", "/dev/stdin", "/dev/stdout")
cmd.Stdin = inBuf
cmd.Stdout = outBuf
err := cmd.Run()
if err != nil {
return nil, err
}
correct, _ := correctOne(stdin)
return outBuf.Bytes()[:len(correct)], nil // diff
}

我假定输出的详细信息包含在/dev/stdout中,因此wrongOne函数不起作用。即

wrongOne的输出=correctOne+[]字节的输出{版权所有2022 Company股份有限公司…成功。}

有什么解决方案可以让我在管道中获得output_file.avi,而无需将其保存为文件并从磁盘读取?谢谢

该命令将版权声明写入stdout。为了避免将版权声明与输出文件混淆,请使用/dev/stdout以外的文件作为输出文件。

下面的函数使用Cmd。ExtraFiles将管道连接到子进程中的fd 3。该函数将数据从管道复制到字节缓冲区,并将这些字节返回给调用方。

func otherOne(stdin []byte) ([]byte, error) {
r, w, err := os.Pipe()
if err != nil {
return nil, err
}
defer r.Close()
defer w.Close()
cmd := exec.Command("./my_bin", "/dev/stdin", "/dev/fd/3")
cmd.Stdin = bytes.NewReader(stdin)
cmd.ExtraFiles = []*os.File{w} // The first file is fd 3.
if err := cmd.Start(); err != nil {
return nil, err
}
w.Close()
var outbuf bytes.Buffer
if _, err := io.Copy(&outbuf, r); err != nil {
return nil, err
}
if err := cmd.Wait(); err != nil {
return nil, err
}
return outbuf.Bytes(), nil
}

几个月后,我找到了解决这个问题的另一种方法。其基本思想与Cerise类似,即使用/dev/fd/3重定向输出文件。之后,我们将/dev/fd/3重定向到/dev/stdout,将详细日志重定向到/dev/stderr3>&11>&2。增加了一个额外的CCD_ 15。解决方案如下:

#gen.sh
./mybin /dev/stdin /dev/fd/3 3>&1 1>&2
// gen.go
func gen(stdin []byte) ([]byte, error) {
inBuf := bytes.NewBuffer(stdin)
outBuf := bytes.NewBuffer(nil)
cmd := exec.Command("./gen.sh")
cmd.Stdin = inBuf
cmd.Stdout = outBuf
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
return nil, err
}
return outBuf.Bytes(), nil
}