If errexit is enabled, how do I run a command that might fail and get an exit code?
All my scripts have included errexit; that is, I run set -o errexit
. However, sometimes I want to run commands like grep
but want to continue executing my script even if the command doesn't work.
How should I do it? That is, how can I get the exit code of a command into a variable without destroying my entire script?
I could disable errexit, but I would rather not.
source to share
Yours errexit
will only terminate the script if the command that doesn't work is "not tested". Per man sh
on FreeBSD:
Exit immediately if any untested command fails in non-interactive
mode. The exit status of a command is considered to be explic-
itly tested if the command is part of the list used to control an
if, elif, while, or until; if the command is the left hand oper-
and of an ``&&'' or ``||'' operator; or if the command is a pipe-
line preceded by the ! keyword.
So, if you were thinking of using a construction like this:
grep -q something /path/to/somefile
retval=$?
if [ $retval -eq 0 ]; then
do_something # found
else
do_something_else # not found
fi
instead, you should use a construction like this:
if grep -q something /path/to/somefile; then
do_something # found
else
do_something_else # not found
fi
The existence of the keyword if
makes the grep command checked , so it is not affected errexit
. And this method requires less input.
Of course, if you really need the output value in a variable, then nothing prevents you from using $?
:
if grep -q something /path/to/somefile; then
do_something # found
else
unnecessary=$?
do_something $unnecessary # not found
fi
source to share
Here's a way to achieve this: you can "disable" set -o errexit
for some lines of code and then re-enable it when you decide:
set +e #disables set -o errexit
grep -i something file.txt
rc="$?" #capturing the return code for last command
set -e #reenables set -o errexit
Another variant:
grep -i something file.txt || rc="$?"
This will allow you to capture the return code for the variable rc
without interrupting your script. You can even extend this last feature to capture and handle return code on the same line without risking an exit:
grep -i something file.txt || rc="$?" && echo rc="$?" > somefile.txt && command || :
The last bit ||:
ensures that the line above always returns return code = 0 (true).
source to share
Most compact and least repetitive form I can think of:
<command> && rc=$? || rc=$?
The form without repeating the variable name - rc=$(<command> && echo $? || echo $?)
- has an rvalue expression, but will also write stdout <command>
1 . Thus, it is safe if you "know" that <command>
there is no normal way out.
Using the constructor a && b || c
's safe , because rc=$?
, and $(echo $?)
never fail.
1 Of course you can get around this by playing around with file descriptors, but that would make the construction long and awkward as standard
source to share