2015-05-13 2 views
6

У меня есть программа go, которая должна вызывать скрипт ruby.golang exec.Command read std input

У меня есть 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, но он не дожидается ввода.

Что я делаю неправильно?

+0

Когда в Ruby есть 'get', вы можете вводить ввод с консоли? Неужели Руби ждет этого? Вы нажимаете Enter после ввода вашего ввода? – icza

+0

'get' находится в середине потока, и если я запустил скрипт ruby, он ждет ввода. Да, я нажимаю Enter после ввода. Мой реальный usecase - вызывать 'pry' на рубиновой стороне, и мое ожидание -' cmd.Run() 'будет ждать завершения' pry' REPL. –

+0

Если я запустил [это простое приложение Go] (http://play.golang.org/p/0eWjtN2RWG) из вашего кода, он отлично работает, ждет ввода и правильно печатает outpout. Я бы сказал, что это что-то в вашем коде Ruby. – icza

ответ

4

Следующая программа, кажется, делать то, что вы просите (мой 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) 
    } 
} 
+0

Спасибо - я, наконец, понял, что это правильный код, и проблема была в другом месте (у меня был множественный уровень перенаправления, и я пропустил один из них). –

2

Возможно, вам потребуется использовать pseudoterminal. Вы можете сделать это в ходу с этой библиотекой: 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 
    `) 
} 
+0

Не знал об этой библиотеке, +1 за то, что представил меня псевдотерминалу в голанге. Проблема была в другом месте, как я упоминал в своем комментарии выше. Благодарю. –

Смежные вопросы