2015-05-13 16 views
6

Ich habe ein Go-Programm, das ein Ruby-Skript aufrufen sollte.Golang exec.Command lesen std Eingabe

Ich habe eine runCommand Funktion:

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) 
    } 
} 

ich es wie folgt aufrufen:

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

Es ist für den meisten Fällen funktioniert, außer wenn es in den untergeordneten Prozess ein gets oder eine ähnliche Operation das muss für eine Eingabe pausiert werden.

Ich habe versucht Einstellung cmd.Stdin = os.Stdin, aber es wartet nicht auf Eingabe.

Was mache ich falsch?

+0

Wenn es in Ruby 'gets 'gibt, können Sie Eingaben von Ihrer Konsole eingeben? Wartet Ruby darauf? Haben Sie nach Eingabe Ihrer Eingabe die Eingabetaste gedrückt? – icza

+0

'gets' ist in der Mitte eines Flusses, und wenn ich das Ruby-Skript ausführen, wartet es auf eine Eingabe. Ja, ich drücke nach der Eingabe die Eingabetaste. Mein wirklicher Anwendungsfall ist es, auf der Ruby-Seite 'pry' aufzurufen, und meine Erwartung ist' cmd.Run() 'würde warten, bis die' PRY'-REPL abgeschlossen ist. –

+0

Wenn ich [diese einfache Go-App] (http://play.golang.org/p/0eWjtN2RWG) von Ihrem Code aus starte, funktioniert es einwandfrei, wartet auf die Eingabe und druckt den output korrekt aus. Ich würde sagen, es ist etwas in Ihrem Ruby-Code. – icza

Antwort

4

Das folgende Programm scheint tun, was Sie fragen für (mein runCommand ist bei Ihnen fast identisch Ich habe gerade die = zu := für die err Linie..) Machst du etwas anderes?

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

Danke - Ich fand schließlich heraus, dass dies ein gültiger Code war, und das Problem war woanders (ich hatte mehrere Umleitungsebenen, und ich vermisste eine davon). –

2

Möglicherweise müssen Sie eine pseudoterminal verwenden. Sie können dies mit dieser Bibliothek in go tun: 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

Ich wusste nichts über diese Bibliothek, +1 für die Einführung in ein Pseudoterminal in Golang. Das Problem war anderswo, wie ich in meinem Kommentar oben erwähnt habe. Vielen Dank. –