I prefer to write solid shell code, so the errexit & nounset is alway set.
The following code will stop at bad_command line
#!/bin/bash
set -o errexit ; set -o nounset
bad_command # stop here
good_command
I want to capture it, here is my method
#!/bin/bash
set -o errexit ; set -o nounset
rc=1
bad_command && rc=0 # stop here
[ $rc -ne 0 ] && do_err_handle
good_command
Is there any better or cleaner method
My Answer:
#!/bin/bash
set -o errexit ; set -o nounset
if ! bad_command ; then
# error handle here
fi
good_command
Continue to write solid shell code.
You do it right if bad_command is really a command. But be careful with function calls in if, while, ||, && or !, because errexit will not work there. It may be dangerous.
If your bad_command is actually bad_function you should write this:
This works well in bash 4.0. In bash 4.2 you only get exit codes 0 or 1.
How about this? If you want the actual exit code ...
Output:
A common way to avoid exiting a Bash program when
errexit
is set and a command that may fail is run is to precede the command with!
.After the command has run
$?
does not contain the exit status of the command. (It contains 0 if the command failed and 1 otherwise.) However, the PIPESTATUS array does contain the exit status of the command. A safe way to capture the exit status of a command that may fail, whether or noterrexit
is set, is:The second line can be simplified to
rc=$PIPESTATUS
, but Shellcheck will complain about it.If (as is often the case) you don't need to know the exit status of the command, just if it succeeded or failed, then the solution by @george is good if the error handler is a one-liner. For multi-line error handlers a good option is:
Note that (except in very unusual circumstances) it would not be correct to use
`bad_command`
(as suggested in the question) instead of plainbad_command
. You can use${PIPESTATUS[0]}
to get the exit status of the command if it is needed in the error handling code, since$?
doesn't contain it in this case either.The accepted answer is good, but I think it could be refactored to be even better; more generic, easier to refactor and read:
vs.
A slight variation of the answer given by @rrauenza. Since the
&& rc=$?
part is their answer will always be equal to&& rc=0
one can as well setrc
to0
before running the command. The result ends up more readable in my opinion because the variable is defined upfront in its own line of code and is only changed if the command exits with a non-zero exit status. Ifnounset
is also given, then it's now clear thatrc
was indeed never undefined. This also avoids mixing&&
and||
in the same line which might be confusing because one might not always know the operator precedence by heart.Output: