2015-06-28 14 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 
} 
相关问题