2016-08-17 78 views
0

我正在寫一個函數,它是exec的程序並返回stdout和stderr。它也可以將輸出顯示到控制檯。我顯然不是在等待某個東西,就像我連續運行兩次函數一樣,輸出結果也不一樣。下面是一個示例程序,用了很多的文件目錄替換DIR VAR填滿緩衝區:Golang - 將exec輸出複製到緩衝區

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 
} 

回答

1

這是您的示例的簡化和工作版本。請注意,測試命令已換出,以便我可以在Windows中進行測試,並且僅爲了簡潔起見您省略了錯誤檢查。

關鍵的變化是,sync.WaitGroup阻止run函數打印輸出並返回,直到goroutine指示它已完成。

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

我看到了一些問題:

  • 你應該等待夠程完成(例如,使用 sync.WaitGroup)。
  • 您正在訪問output同時在兩個 goroutines,這是不安全的。

你可以在兩個不同的緩衝區收集stdoutstderr並單獨返回它們,是否適合你想要做什麼。