Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
All of my scripts have errexit turned on; that is, I run
set -o errexit
. However, sometimes I want to run commands like
grep
, but want to continue execution of my script even if the command fails.
How do I do this? That is, how can I get the exit code of a command into a variable without killing my whole script?
I could turn errexit off, but I'd prefer not to.
–
–
–
–
Your
errexit
will only cause the script to terminate if the command that fails is "untested". 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 construct like this:
grep -q something /path/to/somefile
retval=$?
if [ $retval -eq 0 ]; then
do_something # found
do_something_else # not found
you should instead use a construct like this:
if grep -q something /path/to/somefile; then
do_something # found
do_something_else # not found
The existence of the if
keyword makes the grep command tested, thus unaffected by errexit
. And this way takes less typing.
Of course, if you REALLY need the exit value in a variable, there's nothing stopping you from using $?
:
if grep -q something /path/to/somefile; then
do_something # found
unnecessary=$?
do_something $unnecessary # not found
–
Here's a way to achieve this: you can "turn off" set -o errexit
for some lines of code, and then turn it on again 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 option would be the following:
grep -i something file.txt || rc="$?"
That would allow you to capture the return code on the variable rc
, without interrupting your script. You could even extend this last option to capture and process the return code on the same line without risking to trigger an exit:
grep -i something file.txt || rc="$?" && echo rc="$?" > somefile.txt && command || :
The last bit ||:
will guarantee that the line above always returns a return code = 0 (true).
–
–
–
–
A form without variable name repetition -- rc=$(<command> && echo $? || echo $?)
-- has an expression rvalue but would also capture the stdout of <command>
1. So, it's only safe if you "know" that <command>
has no normal output.
Using the a && b || c
construct is safe here because rc=$?
and $(echo $?)
can never fail.
1Sure, you can work around this by fiddling with file descriptors, but that'd make the construct long-winded and inconvenient as a standard
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.