cmd && echo "$?" wouldn't work since it would by necessity only print zeroes (the echo would only execute on successful completion of the preceding command).
Here's a short shell function for you:
tellexit () {
"$@"
local err="$?"
printf 'exit code\t%d\n' "$err" >/dev/tty
return "$err"
}
This prints the exit code of the given command in a similar manner as the time command does.
$ tellexit echo "hello world"
hello world
exit code 0
$ tellexit false
exit code 1
By redirecting the printf to /dev/tty in the function, we may still use tellexit with redirections without getting junk in our standard output or error streams:
$ tellexit bash -c 'echo hello; echo world >&2' >out 2>err
exit code 0
$ cat out
hello
$ cat err
world
By saving the exit code in a variable we are able to return it to the caller:
$ tellexit false || echo 'failed'
exit code 1
failed
A fancier version of the same function also prints the signal that killed the command if the exit code is greater than 128 (which means it terminated due to a signal):
tellexit () {
"$@"
local err="$?"
if [ "$err" -gt 128 ]; then
printf 'exit code\t%d (%s)\n' "$err" "$(kill -l "$err")" >/dev/tty
else
printf 'exit code\t%d\n' "$err" >/dev/tty
fi
return "$err"
}
Testing:
$ tellexit sh -c 'kill $$'
exit code 143 (TERM)
$ tellexit sh -c 'kill -9 $$'
Killed
exit code 137 (KILL)
(The local thing requires ash/pdksh/bash/zsh, or you can change it to typeset which a few other shells also understand.)
sleep 1 && echo $?would print the sleeper cell's code only when it's zero...sleep 1 && echo "$?" || echo "$?"EXIT_CODE=$(tellexit command)