英文:
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
`)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论