2017-12-07 4 views
1

Ich versuche, einen Shell-Prozess in Go zu starten. Dies ist mein Code:Shell/Bash in Go ausführen

func StartShell() (*Shell, error) { 
    cmd := exec.Command("sh") 

    stderr, err := cmd.StderrPipe() 
    if err != nil { 
     return nil, err 
    } 

    stdin, err := cmd.StdinPipe() 
    if err != nil { 
     return nil, err 
    } 

    stdout, err := cmd.StdoutPipe() 
    if err != nil { 
     return nil, err 
    } 

    if err := cmd.Start(); err != nil { 
     return nil, err 
    } 

    sh := &Shell{ 
     cmd:  cmd, 
     stderr: stderr, 
     stdin:  stdin, 
     stdout: stdout, 
    } 

    // this will read forever, but it is only for ilustrative purposes 
    for { 
     b := make([]byte, 2048) 
     fmt.Println(stdout.Read(b)) 
    } 

    return sh, nil 
} 

Wenn ich oben Funktion ausführen, wie es ist, ich werde keine Ausgabe erhalten, aber wenn ich sh-cmd und führen Sie es unter Windows zu ändern, druckt er einige Daten am Anfang und wartet für immer (das ist OK). Beispiel Ausgabe:

36 <nil> 
129 <nil> 

Dies führte mich zu denken, dass es Linux Weg sein kann. Also habe ich den Befehl in ls geändert und unter Linux ausgeführt. Kurz gesagt: Es funktioniert wie erwartet.

Als nächstes leitete ich stdout, stderr und stdin zu den Prozess ein. Ich habe gerade über cmd.Start() folgende Snippet hinzugefügt:

// without those three below, `sh` would not print anything to stdout 
cmd.Stdout = os.Stdout 
cmd.Stdin = os.Stdin 
cmd.Stderr = os.Stderr 

Wenn nun ausgeführt, ich habe voll funktions sh Prozess zu meinem Terminal umgeleitet. Es funktioniert nur, wenn alle 3 Streams umgeleitet werden.

Warum passiert das? Im Idealfall möchte ich den Shell-Prozess im Hintergrund starten und Befehle innerhalb dieser Shell ausführen, ohne sie auf das Terminal zu drucken. (Ich bin mir bewusst, dass dies keine optimale Lösung ist.)

Antwort

1

Auf einigen Systemen wird ein Prozess erst dann beendet, wenn er seine Daten in stdout/stderr löscht. Daher müssen diese Ströme vollständig entleert werden, bevor der Prozess beendet wird. In ähnlicher Weise versuchen einige Prozesse, stdin vollständig zu lesen, so dass sie einen zu lesenden Stream benötigen, bevor der Prozess beendet wird.

Wenn Sie die Subprozessausgabe nicht in die Standarddatenströme drucken möchten, sollten Sie sie in einen anderen Datenstrom umleiten, der ihre Daten verwendet (z. B. einen Bytepuffer oder discard writer).

+0

Aber für mich wird erwartet, dass der Prozess nicht beendet wird. Ich versuche, die Bytes zu lesen, sobald sie gesendet werden. Ich habe Ihr Snippet eins zu eins implementiert und dann aus dem 'out' Puffer gelesen - immer noch nada. –