dqydp44800
dqydp44800
2015-05-13 06:16
浏览 299
已采纳

golang exec.Command读取标准输入

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
", 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?

图片转代码服务由CSDN问答提供 功能建议

我有一个可以调用ruby脚本的go程序。

I 具有 runCommand 函数:

  func runCommand(cmdName字符串,arg ... string){
 cmd:= exec.Command(cmdName,  arg ...)
 cmd.Stdout = os.Stdout 
 cmd.Stderr = os.Stderr 
 cmd.Stdin = os.Stdin 
 err = cmd.Run()
如果err!= nil {\  n fmt.Printf(“无法启动Ruby。%s 
”,err.Error())
 os.Exit(1)
} 
} 
   
 \  n 

我这样调用它:

  runCommand(“ ruby​​”,“ -e”,“ require'foo'”)
   
 
 

在大多数情况下都可以使用,除非子进程中有 gets 或任何类似的操作需要暂停输入。

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

我在做什么错?

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

2条回答 默认 最新

  • dps69208
    dps69208 2015-05-14 13:03
    已采纳

    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
    ", err.Error())
            os.Exit(1)
        }
    }
    
    点赞 评论
  • douxia2137
    douxia2137 2015-05-13 14:15

    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
      `)
    }
    
    点赞 评论

相关推荐