Sorry for bumping an oldish thread, but I just ran into this trying to propagate an exit code.
I didn't find anything searching that was sufficiently platform-independent, but a little spelunking into the stdlib source bore fruit, so I thought I'd share my solution. If you have an *exec.ExitError it embeds an *os.ProcessState. *os.ProcessState's Sys method returns an interface{} containing the a platform specific type from the syscall package. But all the platform specific types have a method ExitStatus() int. (Even nacl and Plan 9, which fake it). So, given an *exec.ExitError x, to get the exit code you just need to do: exitCode := x.Sys().(interface{ ExitStatus() int }).ExitStatus() I suppose it wouldn't hurt to check that type assertion and return -1 if it fails, though I imagine if that ever happened it would be a bug in a new port. On Thu, Jun 2, 2016 at 4:14 AM, Konstantin Khomoutov <flatw...@users.sourceforge.net> wrote: > On Wed, 1 Jun 2016 23:56:43 +0300 > Janne Snabb <sn...@epipe.com> wrote: > >> You should check if the type of err is *exec.ExitError and in that >> case consider it just as non-zero exit value from the process. >> >> The following snippet from >> https://golang.org/src/os/exec/exec_test.go#L123 clarifies it: >> >> func TestExitStatus(t *testing.T) { >> // Test that exit values are returned correctly >> cmd := helperCommand(t, "exit", "42") >> err := cmd.Run() >> want := "exit status 42" >> >> if werr, ok := err.(*exec.ExitError); ok { >> if s := werr.Error(); s != want { >> t.Errorf("from exit 42 got exit %q, want %q", >> s, want) } >> } else { >> t.Fatalf("expected *exec.ExitError from exit 42; got % >> T: %v", err, err) } >> } > > I'd warn the OP to take this snippet with a hefty grain of salt: while > it's perfectly reasonable for the test suite of an stdlib package to > test the output of os/exec.ExitError.Error(), 3rd-party code must not > rely on the output of the Error() methods of error values of any type to > be predictable and stable -- at least until there's absolutely no > other way to get onto error's details. > > That is, the OP should consider writing a helper function to test the > error returned by os/exec.Cmd.Run() et al to check whether the exit > status is non-zero and discard the error value if so. > > An example: > > ----8<---- > package main > > import ( > "os/exec" > "testing" > ) > > func maybeIgnore(err error) error { > if _, ok := err.(*exec.ExitError); ok { > return nil > } > return err > } > > func TestExitCode(t *testing.T) { > cmd := exec.Command("/bin/sh", "-c", "exit 42") > err := maybeIgnore(cmd.Run()) > if err != nil { > t.Error("Expected nil error, got: %#v", err) > } > cmd = exec.Command("./does not exist, really") > err = maybeIgnore(cmd.Run()) > if err == nil { > t.Error("Expected non-nil error, got nil") > } > } > ----8<---- > > (Save as "whatever_test.go" and run `go test`.) > > -- > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to golang-nuts+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.