我的Go应用程序输出一些文本数据,我需要将其传递给某些外部命令(例如less
)。我没有找到任何方法将此数据传输到syscall.Exec
'ed进程。
作为一种解决方法,我将该文本数据写入临时文件,然后将该文件用作less
的参数:
package main
import (
"io/ioutil"
"log"
"os"
"os/exec"
"syscall"
)
func main() {
content := []byte("temporary file's content")
tmpfile, err := ioutil.TempFile("", "example")
if err != nil {
log.Fatal(err)
}
defer os.Remove(tmpfile.Name()) // Never going to happen!
if _, err := tmpfile.Write(content); err != nil {
log.Fatal(err)
}
if err := tmpfile.Close(); err != nil {
log.Fatal(err)
}
binary, err := exec.LookPath("less")
if err != nil {
log.Fatal(err)
}
args := []string{"less", tmpfile.Name()}
if err := syscall.Exec(binary, args, os.Environ()); err != nil {
log.Fatal(err)
}
}
它可以工作但在文件系统上留下一个临时文件,因为syscall.Exec
将当前Go进程替换为另一个(less
),而延迟os.Remove
将无法运行。这种行为是不可取的。
有没有办法将一些数据传输到外部进程而不留下任何文物?
答案 0 :(得分:2)
您应该使用os/exec
构建一个exec.Cmd
来执行,然后您可以提供您想要的任何io.Reader
作为该命令的stdin。
从文档中的示例:
cmd := exec.Command("tr", "a-z", "A-Z")
cmd.Stdin = strings.NewReader("some input")
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
log.Fatal(err)
}
fmt.Printf("in all caps: %q\n", out.String())
如果您想直接写入命令的标准输入,那么请致电cmd.StdInPipe
以获得您可以写入的io.WriteCloser
。
如果您确实需要exec
该过程代替当前过程,您可以在exec&之前删除该文件,并将该文件描述符作为该程序的stdin提供。
content := []byte("temporary file's content")
tmpfile, err := ioutil.TempFile("", "example")
if err != nil {
log.Fatal(err)
}
os.Remove(tmpfile.Name())
if _, err := tmpfile.Write(content); err != nil {
log.Fatal(err)
}
tmpfile.Seek(0, 0)
err = syscall.Dup2(int(tmpfile.Fd()), syscall.Stdin)
if err != nil {
log.Fatal(err)
}
binary, err := exec.LookPath("less")
if err != nil {
log.Fatal(err)
}
args := []string{"less"}
if err := syscall.Exec(binary, args, os.Environ()); err != nil {
log.Fatal(err)
}