We explored how to create child processes in the previous chapter. Go makes it possible for you to easily check child exit codes, however, it's not straightforward because there is a field in the exec.Cmd struct that has an os.ProcessState attribute.
The os.ProcessState attribute has a Sys method that returns an interface. Its value is a syscall.WaitStatus struct in Unix, which makes it possible to access the exit code using the ExitCode method. This is demonstrated using the following code:
package main
import (
"fmt"
"os"
"os/exec"
"syscall"
)
func exitStatus(state *os.ProcessState) int {
status, ok := state.Sys().(syscall.WaitStatus)
if !ok {
return -1
}
return status.ExitStatus()
}
func main() {
cmd := exec.Command("ls", "__a__")
if err := cmd.Run(); err != nil {
if status := exitStatus(cmd.ProcessState); status == -1 {
fmt.Println(err)
} else {
fmt.Println("Status:", status)
}
}
}
If the command variable cannot be accessed, then the error returned is exec.ExitError and this wraps the os.ProcessState attribute, as follows:
func processState(e error) *os.ProcessState {
err, ok := e.(*exec.ExitError)
if !ok {
return nil
}
return err.ProcessState
}
We can see that obtaining the exit code is not straightforward and requires some typecasting.