I'm having a problem using Ubuntu 14.04 and executing diff
on the command line. Look at the following Go code:
package main
import "fmt"
import "log"
import "os/exec"
func main() {
output, err := exec.Command("diff", "-u", "/tmp/revision-1", "/tmp/revision-4").Output()
if err != nil {
log.Fatalln(err)
}
fmt.Println(string(output))
}
If i execute this using go run test.go
i get the following error:
2015/03/18 14:39:25 exit status 1
exit status 1
So something is going wrong with diff
and it's returning 1
as its exit code. Only the diff
command seems to throw an error. If i use the cat
or wc
command, the code runs fine.
Any ideas why diff
doesn't work here but other commands do?
When you run a program with exec
, you get an error if the exit code was not 0. From the doc:
The returned error is nil if the command runs, has no problems copying stdin, stdout, and stderr, and exits with a zero exit status.
If the command fails to run or doesn't complete successfully, the error is of type *ExitError. Other error types may be returned for I/O problems.
So what happens here is that diff returns an error when the files are different, yet you treat it like a runtime error. Just change your code to reflect that it isn't. It's possible by checking the error.
e.g. something like this:
output, err := exec.Command("diff", "-u", "/tmp/revision-1", "/tmp/revision-4").CombinedOutput()
if err != nil {
switch err.(type) {
case *exec.ExitError:
// this is just an exit code error, no worries
// do nothing
default: //couldnt run diff
log.Fatal(err)
}
}
Also, I've changed it get CombinedOutput
, so if any diff specific errors occured, you'll see stderr as well.
Note that you'll get a "valid" error even if one of the files doesn't exist. So you can check the ExitError
's exit code by doing something like this:
switch e := err.(type) {
case *exec.ExitError:
// we can check the actual error code. This is not platform portable
if status, ok := e.Sys().(syscall.WaitStatus); ok {
// exit code 1 means theres a difference and is not an error
if status.ExitStatus() != 1 {
log.Fatal(err)
}
}