golang exec.Command read std input

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

golang exec.Command read std input

问题

我有一个Go程序,应该调用一个Ruby脚本。

我有一个runCommand函数:

func runCommand(cmdName string, arg ...string) {
    cmd := exec.Command(cmdName, arg...)
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    cmd.Stdin = os.Stdin
    err = cmd.Run()
    if err != nil {
        fmt.Printf("Failed to start Ruby. %s\n", err.Error())
        os.Exit(1)
    }
}

我像这样调用它:

runCommand("ruby", "-e", "require 'foo'")

它对大多数情况都有效,但是如果子进程中有一个需要暂停等待输入的gets或类似操作,则无效。

我尝试设置cmd.Stdin = os.Stdin,但它不会等待输入。

我做错了什么?

英文:

I have a go program that should invoke a ruby script.

I have a runCommand function:

func runCommand(cmdName string, arg ...string) {
	cmd := exec.Command(cmdName, arg...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	err = cmd.Run()
	if err != nil {
		fmt.Printf("Failed to start Ruby. %s\n", err.Error())
		os.Exit(1)
	}
}

I invoke it like this:

runCommand("ruby", "-e", "require 'foo'")

It works for most cases, except if there is a gets or any similar operation in the child process that needs to pause for an input.

I have tried setting cmd.Stdin = os.Stdin, but it does not wait for input.

What am I doing wrong?

答案1

得分: 8

以下是翻译好的内容:

以下程序似乎可以实现你所要求的功能(我的runCommand函数与你的几乎完全相同,只是将=更改为:=,用于err行)。你是在做一些不同的事情吗?

package main

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

func main() {
	runCommand("ruby", "-e", `puts "Running"; $in = gets; puts "You said #{$in}"`)
}

func runCommand(cmdName string, arg ...string) {
	cmd := exec.Command(cmdName, arg...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	err := cmd.Run()
	if err != nil {
		fmt.Printf("Failed to start Ruby. %s\n", err.Error())
		os.Exit(1)
	}
}
英文:

The following program seems do what you ask for (my runCommand is almost identical to yours. I just changed the = to := for the err line.) Are you doing something differently?

package main

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

func main() {
	runCommand("ruby", "-e", `puts "Running"; $in = gets; puts "You said #{$in}"`)
}

func runCommand(cmdName string, arg ...string) {
	cmd := exec.Command(cmdName, arg...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	err := cmd.Run()
	if err != nil {
		fmt.Printf("Failed to start Ruby. %s\n", err.Error())
		os.Exit(1)
	}
}

答案2

得分: 7

你可能需要使用一个伪终端(pseudoterminal)。你可以使用go语言中的这个库来实现:github.com/kr/pty

package main

import (
	"bufio"
	"io"
	"log"
	"os"
	"os/exec"

	"github.com/kr/pty"
)

func runCommand(cmdName string, arg ...string) {
	cmd := exec.Command(cmdName, arg...)
	tty, err := pty.Start(cmd)
	if err != nil {
		log.Fatalln(err)
	}
	defer tty.Close()

	go func() {
		scanner := bufio.NewScanner(tty)
		for scanner.Scan() {
			log.Println("[" + cmdName + "] " + scanner.Text())
		}
	}()
	go func() {
		io.Copy(tty, os.Stdin)
	}()

	err = cmd.Wait()
	if err != nil {
		log.Fatalln(err)
	}
}

func main() {
	log.SetFlags(0)
	runCommand("ruby", "-e", `
puts "Enter some text"
text = gets
puts text
  `)
}
英文:

You might need to use a pseudoterminal. You can do this in go with this library: github.com/kr/pty:

package main

import (
	"bufio"
	"io"
	"log"
	"os"
	"os/exec"

	"github.com/kr/pty"
)

func runCommand(cmdName string, arg ...string) {
	cmd := exec.Command(cmdName, arg...)
	tty, err := pty.Start(cmd)
	if err != nil {
		log.Fatalln(err)
	}
	defer tty.Close()

	go func() {
		scanner := bufio.NewScanner(tty)
		for scanner.Scan() {
			log.Println("[" + cmdName + "] " + scanner.Text())
		}
	}()
	go func() {
		io.Copy(tty, os.Stdin)
	}()

	err = cmd.Wait()
	if err != nil {
		log.Fatalln(err)
	}
}

func main() {
	log.SetFlags(0)
	runCommand("ruby", "-e", `
puts "Enter some text"
text = gets
puts text
  `)
}

huangapple
  • 本文由 发表于 2015年5月13日 14:16:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/30207035.html
匿名

发表评论

匿名网友

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

确定