-
Notifications
You must be signed in to change notification settings - Fork 18.3k
Description
After a bit of discussion on this golang-nuts thread, I propose that we add an ExitStatus() int
method to os.ProcessState
so that it's significantly simpler to get the exit status of a finished process, and doesn't require the syscall package.
Motivation (some of this copied from the thread): I struggled to get the exit status integer of a command executed with os/exec. I followed the documentation through ExitError and ProcessState, but could only find the ProcessState.Success() boolean. After searching Google+StackOverflow I found you can get it, but it requires importing syscall and converting to a syscall type -- pretty klunky.
Here's roughly the code snippet that I'm currently using:
err = cmd.Wait()
if err != nil {
if exitErr, ok := err.(*exec.ExitError); ok {
if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
return status.ExitStatus()
}
}
return -1
}
return 0
Which is problematic because of all the boilerplate, but also because syscall is platform-specific, and fetching an exit code works on all major platforms (Unix/Linux/macOS/Windows). Even on Plan 9 ExitStatus() is implemented (though admittedly it's a bit of a hack as it just checks to see whether an error message was returned). So this would work for all major systems, and on Plan 9 would just act like the above syscall function that already exists, returning 0 on success or 1 on error.
os.ProcessState
already has a Success() bool
method, so this proposal would add ExitStatus() int
alongside that. It would return the exit status integer (and possibly be documented to return -1 if the process hasn't finished). This would enable the above code to be something like this:
err = cmd.Wait()
if err != nil {
if exitErr, ok := err.(*exec.ExitError); ok {
return exitErr.ExitStatus() // ExitError embeds ProcessState
}
return -1
}
return 0
Or actually just this:
_ = cmd.Wait()
return cmd.ProcessState.ExitStatus()
There are various reasons for needing the exit code value:
- To log it in a structured way
- To switch on the exit code when running a utility that returns different well-defined codes for different kinds of errors that you need to detect
- To display it in (say) a bold font in a UI control
- To return it from a
system()
function when implementing a scripting language (my particular case)
This exists in other languages, for example Python's subprocess has "returncode" and Java's exec has exitValue().
For what it's worth, @ianlancetaylor said (on the linked golang-nuts thread) that this "seems reasonable to me".