如何在子进程中从`exec.Cmd`的ExtraFiles文件描述符中读取数据?

huangapple go评论89阅读模式
英文:

How can I read from `exec.Cmd` ExtraFiles fd in child process?

问题

我从golang.org上阅读了解释,它的说明如下:

// ExtraFiles指定要由新进程继承的其他打开文件。它不包括标准输入、标准输出或标准错误。如果非nil,则第i个条目变为文件描述符3+i。

BUG:在OS X 10.6上,子进程有时可能会继承不需要的文件描述符。http://golang.org/issue/2603

我对此不太理解。例如,我有以下代码:

cmd := &exec.Cmd{
Path: init,
Args: initArgs,
}
cmd.Stdin = Stdin
cmd.Stdout = Stdout
cmd.Stderr = Stderr
cmd.Dir = Rootfs
cmd.ExtraFiles = []*os.File{childPipe}

这是否意味着,由于我在cmd.ExtraFiles = []*os.File{childPipe}中写入了一个childPipe,我可以通过直接写入fd 3来使用它?

pipe = os.NewFile(uintptr(3), "pipe")
json.NewEncoder(pipe).Encode(newThing)

如果有人能提供帮助,谢谢!

英文:

I read the explanation from golang.org, it says like below.

// ExtraFiles specifies additional open files to be inherited by the
// new process. It does not include standard input, standard output, or
// standard error. If non-nil, entry i becomes file descriptor 3+i.
//
// BUG: on OS X 10.6, child processes may sometimes inherit unwanted fds.
// http://golang.org/issue/2603
ExtraFiles []*os.File

I'm not very understand about it ? For example I have such code below.

cmd := &exec.Cmd{
	Path: init,
	Args: initArgs,
}
cmd.Stdin = Stdin
cmd.Stdout = Stdout
cmd.Stderr = Stderr
cmd.Dir = Rootfs
cmd.ExtraFiles = []*os.File{childPipe}

Is that mean, since I have written a childpipe in cmd.ExtraFiles = []*os.File{childPipe}, I can use it by writing fd 3 directly.

pipe = os.NewFile(uintptr(3), "pipe")
json.NewEncoder(pipe).Encode(newThing)

Thanks if anyone can give some help!

答案1

得分: 6

正确;您可以通过创建一个新的*File,其文件描述符是子进程管道的文件描述符,从管道中读取数据。以下是将数据从子进程传输到父进程的示例:

父进程:

package main

import (
	"fmt"
	"os/exec"
	"os"
	"encoding/json"
)

func main() {
	init := "child"
	initArgs := []string{"hello world"}

	r, w, err := os.Pipe()
	if err != nil {
		panic(err)
	}

	cmd := exec.Command(init, initArgs...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.ExtraFiles = []*os.File{w}

	if err := cmd.Start(); err != nil {
		panic(err)
	}
	var data interface{}
	decoder := json.NewDecoder(r)
	if err := decoder.Decode(&data); err != nil {
		panic(err)
	}
	fmt.Printf("从子进程管道接收到的数据:%v\n", data)
}

子进程:

package main

import (
	"os"
	"encoding/json"
	"strings"
	"fmt"
)

func main() {
	if len(os.Args) < 2 {
		os.Exit(1)
	}
	arg := strings.ToUpper(os.Args[1])

	pipe := os.NewFile(uintptr(3), "pipe")
	err := json.NewEncoder(pipe).Encode(arg)
	if err != nil {
		panic(err)
	}
	fmt.Println("此消息打印到标准输出,而不是管道")
}
英文:

Correct; you can read from the pipe by creating a new *File whose file descriptor is that of the child pipe. Below is a example of piping data from the child process to the parent:

Parent:

package main

import (
	&quot;fmt&quot;
	&quot;os/exec&quot;
	&quot;os&quot;
	&quot;encoding/json&quot;
)

func main() {
	init := &quot;child&quot;
	initArgs := []string{&quot;hello world&quot;}

	r, w, err := os.Pipe()
	if err != nil {
		panic(err)
	}

	cmd := exec.Command(init, initArgs...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.ExtraFiles = []*os.File{w}

	if err := cmd.Start(); err != nil {
		panic(err)
	}
	var data interface{}
	decoder := json.NewDecoder(r)
	if err := decoder.Decode(&amp;data); err != nil {
		panic(err)
	}
	fmt.Printf(&quot;Data received from child pipe: %v\n&quot;, data)
}

Child:

package main

import (
	&quot;os&quot;
	&quot;encoding/json&quot;
	&quot;strings&quot;
	&quot;fmt&quot;
)

func main() {
	if len(os.Args) &lt; 2 {
		os.Exit(1)
	}
	arg := strings.ToUpper(os.Args[1])

	pipe := os.NewFile(uintptr(3), &quot;pipe&quot;)
	err := json.NewEncoder(pipe).Encode(arg)
	if err != nil {
		panic(err)
	}
	fmt.Println(&quot;This message printed to standard output, not to the pipe&quot;)
}

huangapple
  • 本文由 发表于 2015年4月9日 10:34:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/29528756.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定