80

When I run the code below:

cmd := exec.Command("find", "/", "-maxdepth", "1", "-exec", "wc", "-c", "{}", "\\")
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
    fmt.Println(err)
    return
}
fmt.Println("Result: " + out.String())

I am getting this error:

exit status 1

However this is not helpful to debug the exact cause of the error.

How to get more detailed information?

laurent
  • 88,262
  • 77
  • 290
  • 428

2 Answers2

154

The solution is to use the Stderr property of the Command object. This can be done like this:

cmd := exec.Command("find", "/", "-maxdepth", "1", "-exec", "wc", "-c", "{}", "\\")
var out bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
    fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
    return
}
fmt.Println("Result: " + out.String())

Running the above code, would make it clear what the issue is:

exit status 1: find: -exec: no terminating ";" or "+"

Edit:

In the code above, we expect that in case of error, the messages will be printed to stderr and the command will return a non-zero error code. This is more or less standard.

However, as mentioned below by @snorberhuis, some commands print the errors to stdout. Other commands might print to stderr but return an error code of 0 (in which case err will be nil). And having messages in stderr doesn't necessarily mean there's an error (ffmpeg tools do this a lot).

So basically you might need to tweak the code above to accommodate the commands you expect.

laurent
  • 88,262
  • 77
  • 290
  • 428
  • 1
    Your solution is very helpful for debugging, but I had to do a minor change for me to actually see output. I was debugging the Windows shutdown command also with exit status 1. This prints to `Stdout`. So I moved the last line of printing out above the if statement. – snorberhuis Oct 24 '16 at 09:32
  • 2
    This solution is better than `CombinedOutput()` as here we get detailed error text (of cmd.Stderr). In `output, err := cmd.CombinedOutput()` , `output` does contain error text but its same as `err`. – fiberair Nov 24 '17 at 10:00
60

As Laurent mentioned, you can override the Stderr file descriptor to capture the stderr output for a better error message. I personally prefer to use the CombinedOutput method for a command if doing something relatively simple:

cmd := exec.Command("find", "/", "-maxdepth", "1", "-exec", "wc", "-c", "{}", "\\")
output, err := cmd.CombinedOutput()
if err != nil {
    fmt.Println(fmt.Sprint(err) + ": " + string(output))
    return
}
fmt.Println(string(output))

Here's a play.golang.org link for the above example: http://play.golang.org/p/z8k9zO755P

Yves Junqueira
  • 755
  • 6
  • 18
noj
  • 2,542
  • 1
  • 14
  • 9