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.

+3


source to share


3 answers


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

      

+4


source


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).

+1


source


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

+1


source







All Articles