2016-08-17 2 views
0

Ich schreibe eine Funktion, die Exec ist ein Programm und gibt stdout und stderr zurück. Es hat auch die Option, die Ausgabe auf der Konsole anzuzeigen. Ich warte eindeutig nicht auf etwas, als ob ich die Funktion zweimal hintereinander ausführen würde, die Ausgänge sind unterschiedlich. Hier ist ein Beispielprogramm, ersetzen Sie das Verzeichnis var mit dir mit einer Menge von Dateien, die Puffer zu füllen:Golang - Kopiere Exec-Ausgabe in einen Puffer

func main() { 
    dir := "SOMEDIRECTORYWITHALOTOFFILES" 
    out, err := run("ls -l "+dir, true) 
    if err != nil { 
     log.Fatalf("run returned %s", err) 
    } 
    log.Printf("Out: %s", out) 
    out2, err := run("ls -l "+dir, false) 
    if err != nil { 
     log.Fatalf("run returned %s", err) 
    } 
    log.Printf("Out2: %s", out2) 
    if out != out2 { 
     log.Fatalf("Out mismatch") 
    } 
} 

func run(cmd string, displayOutput bool) (string, error) { 
    var command *exec.Cmd 
    command = exec.Command("/bin/sh", "-c", cmd) 
    var output bytes.Buffer 

    stdout, err := command.StdoutPipe() 
    if err != nil { 
     return "", fmt.Errorf("Unable to setup stdout for command: %v", err) 
    } 
    go func() { 
     if displayOutput == true { 
      w := io.MultiWriter(os.Stdout, &output) 
      io.Copy(w, stdout) 
     } else { 
      output.ReadFrom(stdout) 
     } 
    }() 

    stderr, err := command.StderrPipe() 
    if err != nil { 
     return "", fmt.Errorf("Unable to setup stderr for command: %v", err) 
    } 
    go func() { 
     if displayOutput == true { 
      w := io.MultiWriter(os.Stderr, &output) 
      io.Copy(w, stderr) 
     } else { 
      output.ReadFrom(stderr) 
     } 
    }() 
    err = command.Run() 
    if err != nil { 
     return "", err 
    } 
    return output.String(), nil 
} 

Antwort

1

Hier ist eine vereinfachte und funktionierende Überarbeitung Ihres Beispiels. Beachten Sie, dass der Testbefehl ausgelagert wurde, so dass ich in Windows testen konnte und dass Ihre Fehlerüberprüfungen nur der Kürze wegen weggelassen wurden.

Die Schlüsseländerung ist, dass ein sync.WaitGroup verhindert, dass die run Funktion die Ausgabe druckt und zurückkehrt, bis die Goroutine angezeigt hat, dass es beendet ist.

func main() { 
    dir := "c:\\windows\\system32" 
    command1 := exec.Command("cmd", "/C", "dir", "/s", dir) 
    command2 := exec.Command("cmd", "/C", "dir", "/s", dir) 
    out1, _ := run(command1) 
    out2, _ := run(command2) 
    log.Printf("Length [%d] vs [%d]\n", len(out1), len(out2)) 
} 

func run(cmd *exec.Cmd) (string, error) { 
    var output bytes.Buffer 
    var waitGroup sync.WaitGroup 

    stdout, _ := cmd.StdoutPipe() 
    writer := io.MultiWriter(os.Stdout, &output) 

    waitGroup.Add(1) 
    go func() { 
     defer waitGroup.Done() 
     io.Copy(writer, stdout) 
    }() 

    cmd.Run() 
    waitGroup.Wait() 
    return output.String(), nil 
} 
0

ich einige Probleme sehen:

  • Sie warten sollten für die goroutines zu beenden (zB unter Verwendung von sync.WaitGroup).
  • Sie greifen auf output gleichzeitig in zwei goroutines, die nicht sicher ist.

Sie könnten stdout und stderr in zwei getrennten Puffern sammeln und separat zurückgeben, ob das funktioniert für das, was Sie zu tun versuchen.

Verwandte Themen