英文:
Pipe to exec'ed process
问题
我的Go应用程序输出一些文本数据,我需要将其导入到某个外部命令(例如less
)中。我没有找到任何将这些数据导入到syscall.Exec
进程中的方法。
作为一种解决方法,我将文本数据写入临时文件,然后将该文件作为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()) // 永远不会执行!
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
会用另一个进程(less
)替换当前的Go进程,而延迟的os.Remove
不会执行。这种行为是不可取的。
有没有办法在不留下任何痕迹的情况下将数据导入到外部进程中?
英文:
My Go application outputs some amounts of text data and I need to pipe it to some external command (e.g. less
). I haven't find any way to pipe this data to syscall.Exec
'ed process.
As a workaround I write that text data to a temporary file and then use that file as an argument to 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)
}
}
It works but leaves a temporary file on a file system, because syscall.Exec
replaces the current Go process with another (less
) one and deferred os.Remove
won't run. Such behaviour is not desirable.
Is there any way to pipe some data to an external process without leaving any artefacts?
答案1
得分: 2
你应该使用os/exec
来构建一个exec.Cmd
来执行命令,然后你可以提供任何你想要的io.Reader
作为命令的标准输入。
从文档中的示例可以看出:
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
之前删除文件,并将该文件描述符作为程序的标准输入。
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)
}
英文:
You should be using os/exec
to build an exec.Cmd
to execute, then you could supply any io.Reader
you want as the stdin for the command.
From the example in the documentation:
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())
If you want to write directly to the command's stdin, then you call cmd.StdInPipe
to get an io.WriteCloser
you can write to.
If you really need to exec
the process in place of your current one, you can simply remove the file before exec'ing, and provide that file descriptor as stdin for the program.
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)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论