2015-06-28 13 views
3

我正在執行golang應用程序中的bash命令。現在stdoutstderr直接進入控制檯:將cmd stdout和stderr作爲字符串返回,而不是打印到golang中的控制檯

cmd.Stdout = os.Stdout 
cmd.Stderr = os.Stderr 

但我想stdoutstderr無需立即打印到控制檯返回從runBashCommandAndKillIfTooSlow函數字符串變量。 如何實現這個?

代碼:

package main 

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

func main() { 
    ok, outString, errString := runBashCommandAndKillIfTooSlow("ls -la", 2000) 
    fmt.Println("ok") 
    fmt.Println(ok) 
    fmt.Println("outString") 
    fmt.Println(outString) 
    fmt.Println("errString") 
    fmt.Println(errString) 
} 

/* 
run bash command and kill it if it works longer than "killInMilliSeconds" milliseconds 
*/ 
func runBashCommandAndKillIfTooSlow(command string, killInMilliSeconds time.Duration) (okResult bool, stdout, stderr string) { 
    fmt.Println("running bash command...") 
    fmt.Println(command) 
    cmd := exec.Command("sh", "-c", command) 

    cmd.Stdout = os.Stdout // cmd.Stdout -> stdout 
    cmd.Stderr = os.Stderr // cmd.Stderr -> stderr 

    okResult = true 

    err := cmd.Start() 
    log.Printf("Waiting for command to finish...") 
    done := make(chan error, 1) 
    go func() { 
     done <- cmd.Wait() 
    }() 
    select { 
    case <-time.After(killInMilliSeconds * time.Millisecond): 
     if err := cmd.Process.Kill(); err != nil { 
      log.Fatal("failed to kill: ", err) 
      okResult = false 
     } 
     <-done // allow goroutine to exit 
     // log.Println("process killed") 
    case err := <-done: 

     if err != nil { 
      log.Printf("process done with error = %v", err) 
      okResult = false 
     } 
    } 
    if err != nil { 
     log.Fatal(err) 
     okResult = false 
    } 
    return 
} 

順便說一句,該方案應保持其殺死bash命令,如果它是太慢(killInMilliSeconds參數)的能力。

回答

8

設置輸出到bytes.Buffer

stdout := outbuf.String() 
stderr := errbuf.String() 
2

您可以簡化這個:

var outbuf, errbuf bytes.Buffer 
cmd.Stdout = &outbuf 
cmd.Stderr = &errbuf 

運行該命令後,可以通過調用Buffer.String()方法得到的輸出和錯誤作爲一個字符串通過使用cmd.Run()而不是cmd.Start()讓它自動等待它完成,並使用exec.CommandContext()使其超時。這也將以正確的順序輸出,而原來的程序由於去例行程序而失序。

這裏的簡化,使用@Mello旱獺的答案完全相同的程序:

package main 

import (
    "bytes" 
    "fmt" 
    "log" 
    "os" 
    "os/exec" 
    "time" 

    "golang.org/x/net/context" 
) 

func main() { 
    ctx := context.Background() 
    ok, outString, errString := runBashCommandAndKillIfTooSlow(ctx, "ls -la", 2000*time.Millisecond) 
    fmt.Println("ok") 
    fmt.Println(ok) 
    fmt.Println("outString") 
    fmt.Println(outString) 
    fmt.Println("errString") 
    fmt.Println(errString) 
} 

/* 
run bash command and kill it if it works longer than "killIn" 
*/ 
func runBashCommandAndKillIfTooSlow(ctx context.Context, command string, killIn time.Duration) (okResult bool, stdout, stderr string) { 
    fmt.Println("running bash command...") 
    fmt.Println(command) 
    ctx, _ = context.WithTimeout(ctx, killIn) 
    cmd := exec.CommandContext(ctx, "sh", "-c", command) 

    // Set output to Byte Buffers 
    var outb, errb bytes.Buffer 
    cmd.Stdout = &outb 
    cmd.Stderr = &errb 

    okResult = true 
    err := cmd.Run() 
    stdout = outb.String() 
    stderr = errb.String() 
    if err != nil { 
     log.Fatal(err) 
     okResult = false 
    } 
    return 
} 
相關問題