Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If errexit is on, how do I run a command that might fail and get its exit code?

Tags:

bash

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.

like image 314
Nate Rook Avatar asked May 20 '17 01:05

Nate Rook


People also ask

How would you exit a Linux script when any of the commands in the script fails to execute?

Exit When Any Command Fails This can actually be done with a single line using the set builtin command with the -e option. Putting this at the top of a bash script will cause the script to exit if any commands return a non-zero exit code.

Does a bash script exit on error?

An exit status code is returned when any Linux command is executed from the terminal, either the command is successful or unsuccessful. This status code can be used to show the error message for unsuccessful execution or perform any particular task by using shell script.

How do I exit bin bash?

One of the many known methods to exit a bash script while writing is the simple shortcut key, i.e., “Ctrl+X”. While at run time, you can exit the code using “Ctrl+Z”.

What is Pipefail in bash?

pipefail. If set, the return value of a pipeline is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands in the pipeline exit successfully. This option is disabled by default.


2 Answers

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
else
  do_something_else  # not found
fi

you should instead use a construct like this:

if grep -q something /path/to/somefile; then
  do_something  # found
else
  do_something_else  # not found
fi

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
else
  unnecessary=$?
  do_something $unnecessary  # not found
fi
like image 141
ghoti Avatar answered Sep 26 '22 01:09

ghoti


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

like image 44
Jamil Said Avatar answered Sep 23 '22 01:09

Jamil Said