Go:与另一个进程的双向通信?

标签 go popen

(注意)不是 Go Inter-Process Communication 的骗局这是在询问 System V IPC。 (尾注)

使用 os/exec,我如何与另一个进程交互通信?我想获取进程的标准输入和标准输出的 fd,并使用这些 fds 写入和读取进程。

我发现的大多数示例都涉及运行另一个进程,然后吞噬生成的输出。

这是我正在寻找的 python 等价物。

p = subprocess.Popen("cmd", stdin=subprocess.PIPE, stdout=subprocess.PIPE)
(child_stdin, child_stdout) = (p.stdin, p.stdout)

作为一个具体的例子,考虑打开一个到 dc 的管道,发送行 12 34 +p 并接收行 46

(更新)

func main() {
  cmd := exec.Command("dc")
  stdin, err := cmd.StdinPipe()
  must(err)
  stdout, err := cmd.StdoutPipe()
  must(err)

  err = cmd.Start()
  must(err)

  fmt.Fprintln(stdin, "2 2 +p")

  line := []byte{}
  n, err := stdout.Read(line)

  fmt.Printf("%d :%s:\n", n, line)
}

我通过 strace 看到 dc 正在按预期接收和应答:

[pid  8089] write(4, "12 23 +p\n", 9 <unfinished ...>
...
[pid  8095] <... read resumed> "12 23 +p\n", 4096) = 9
...
[pid  8095] write(1, "35\n", 3 <unfinished ...>

但我似乎没有将结果返回到我的调用程序中:

0 ::

(更新)

根据接受的答案,我的问题是没有分配字符串来接收响应。更改为 line := make([]byte, 100) 修复了所有问题。

最佳答案

exec.Cmd 具有您可以分配的进程 stdin、std 和 stderr 字段。

    // Stdin specifies the process's standard input.
    // If Stdin is nil, the process reads from the null device (os.DevNull).
    // If Stdin is an *os.File, the process's standard input is connected
    // directly to that file.
    // Otherwise, during the execution of the command a separate
    // goroutine reads from Stdin and delivers that data to the command
    // over a pipe. In this case, Wait does not complete until the goroutine
    // stops copying, either because it has reached the end of Stdin
    // (EOF or a read error) or because writing to the pipe returned an error.
    Stdin io.Reader

    // Stdout and Stderr specify the process's standard output and error.
    //
    // If either is nil, Run connects the corresponding file descriptor
    // to the null device (os.DevNull).
    //
    // If Stdout and Stderr are the same writer, at most one
    // goroutine at a time will call Write.
    Stdout io.Writer
    Stderr io.Writer

如果你想要一个预制的管道连接到其中任何一个,你可以使用 *Pipe() 方法

func (c *Cmd) StderrPipe() (io.ReadCloser, error)
func (c *Cmd) StdinPipe() (io.WriteCloser, error)
func (c *Cmd) StdoutPipe() (io.ReadCloser, error)

使用 dc 程序的基本示例(无错误检查):

cmd := exec.Command("dc")
stdin, _ := cmd.StdinPipe()
stdout, _ := cmd.StdoutPipe()
cmd.Start()

stdin.Write([]byte("12 34 +p\n"))

out := make([]byte, 1024)
n, _ := stdout.Read(out)

fmt.Println("OUTPUT:", string(out[:n]))

// prints "OUTPUT: 46"

关于Go:与另一个进程的双向通信?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39799415/

相关文章:

go - 为 TOML 文件和 golang 解析表中的键值对

xml - 如何从golang中的XML文件中提取多个字段

Python:在 git-bash 环境中运行 python 脚本

c - 为什么 dup() 和 popen() 在从另一个进程调用时会阻止我的进程退出?

python - 使用不同的 Python 版本调用 Python 函数最接近的方法是什么?

带有 Go 插件的 Dockerfile

mysql - 如何避免(处理)插入操作的死锁?

file - 在 Go 中获取给定文件描述符的文件大小

php - 在 Windows 上的 PHP 中执行并获取 pid 后台进程

c - fgets() 在 popen() 之后不起作用