100 votes

Rediriger le tuyau stdout du processus enfant en Go

J'écris un programme en Go qui exécute un programme de type serveur (également en Go). Maintenant, je veux avoir le stdout du programme enfant dans ma fenêtre de terminal où j'ai lancé le programme parent. Une façon de le faire est d'utiliser la fonction cmd.Output() mais celle-ci n'imprime le stdout qu'après la sortie du processus. (C'est un problème car ce programme de type serveur fonctionne pendant longtemps et je veux lire le journal de sortie).

La variable out est de type io.ReadCloser et je ne sais pas ce que je dois en faire pour réaliser ma tâche, et je ne trouve rien d'utile sur le web à ce sujet.

func main() {
    cmd := exec.Command("/path/to/my/child/program")
    out, err := cmd.StdoutPipe()
    if err != nil {
        fmt.Println(err)
    }
    err = cmd.Start()
    if err != nil {
        fmt.Println(err)
    }
    //fmt.Println(out)
    cmd.Wait()
} 

Explication du code : décommentez le champ Println pour que le code soit compilé, je sais que Println(out io.ReadCloser) n'est pas une fonction significative.
(il produit la sortie &{3 |0 <nil> 0} ) Ces deux lignes sont juste nécessaires pour que le code se compile.

196voto

cmccabe Points 718

Maintenant je veux avoir le stdout du programme enfant dans ma fenêtre de terminal où j'ai lancé le programme parent.

Pas besoin de s'embêter avec des tuyaux ou des goroutines, celui-ci est facile.

func main() {
    // Replace `ls` (and its arguments) with something more interesting
    cmd := exec.Command("ls", "-l")
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    cmd.Run()
}

18voto

ruakh Points 68789

Je crois que si vous importez io et os et remplacer ceci :

//fmt.Println(out)

avec ça :

go io.Copy(os.Stdout, out)

(voir la documentation pour io.Copy et pour os.Stdout ), il fera ce que vous voulez. (Avis de non-responsabilité : non testé).

Au fait, vous voudrez probablement capturer l'erreur standard aussi, en utilisant la même approche que pour la sortie standard, mais avec cmd.StderrPipe et os.Stderr .

14voto

elimisteve Points 342

Pour ceux qui n'ont pas besoin de cette fonction dans une boucle, mais qui souhaitent que la sortie de la commande soit affichée dans le terminal sans que l'option cmd.Wait() bloquer d'autres déclarations :

package main

import (
    "fmt"
    "io"
    "log"
    "os"
    "os/exec"
)

func checkError(err error) {
    if err != nil {
        log.Fatalf("Error: %s", err)
    }
}

func main() {
    // Replace `ls` (and its arguments) with something more interesting
    cmd := exec.Command("ls", "-l")

    // Create stdout, stderr streams of type io.Reader
    stdout, err := cmd.StdoutPipe()
    checkError(err)
    stderr, err := cmd.StderrPipe()
    checkError(err)

    // Start command
    err = cmd.Start()
    checkError(err)

    // Don't let main() exit before our command has finished running
    defer cmd.Wait()  // Doesn't block

    // Non-blockingly echo command output to terminal
    go io.Copy(os.Stdout, stdout)
    go io.Copy(os.Stderr, stderr)

    // I love Go's trivial concurrency :-D
    fmt.Printf("Do other stuff here! No need to wait.\n\n")
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X