Bash Functions Ignore Set -E

Bash functions ignore set -e

I ended up wrapping the code to do so in a utility function below.

#!/bin/bash -e

# Runs given code aborting on first error and taking desired action on failure
# $1 code to invoke, can be expression or function name
# $2 error handling code, can be function name or expressions
function saferun {
set +e
(set -E ; trap 'exit 1' ERR ; eval $1)
[ $? -ne 0 ] && eval $2
set -e
}

function foo() {
echo Entering foo
false
echo Should not reach this line
}

saferun foo "echo I want to see this line on failure in foo"
foo

Let's break it down:

  • set +e and set -e are used to suppress failure on error, as otherwise the script will just exit on first error
  • trap is used to abort the execution on any error (instead of set -e) () is used to run the given code in subshell, so outer script will keep running after failure, and set -E is used to pass the trap into the subshell. so (set -E ; trap 'exit 1' ERR ; eval $1) run the given code / function aborting on first error while not exiting the whole script
  • $? -ne 0 check for failures and eval $2 runs the error handling code

Bash ignoring error for a particular command

The solution:

particular_script || true

Example:

$ cat /tmp/1.sh
particular_script()
{
false
}

set -e

echo one
particular_script || true
echo two
particular_script
echo three

$ bash /tmp/1.sh
one
two

three will be never printed.

Also, I want to add that when pipefail is on,
it is enough for shell to think that the entire pipe has non-zero exit code
when one of commands in the pipe has non-zero exit code (with pipefail off it must the last one).

$ set -o pipefail
$ false | true ; echo $?
1
$ set +o pipefail
$ false | true ; echo $?
0

With set -e, is it possible to ignore errors for certain commands?

Add || : (or anything else that is guaranteed not to fail but that's the simplest) to the end of the command.

Though many people would simply tell you that set -e isn't worth it because it isn't as useful as you might think (and causes issues like this) and manual error checking is a better policy.

(I'm not in that camp yet though the more I run into issues like this the more I think I might get there one day.)

From thatotherguy's comment explaining one of major the issues with set -e:

The problem with set -e isn't that you have to be careful about which commands you want to allow to fail. The problem is that it doesn't compose. If someone else reads this post and uses source yourfile || : to source this script while allowing failure, suddenly yourfile will no longer stop on errors anywhere. Not even on failing lines after an explicit set -e.

How to disable set -e and set -o

For all options, the opposite of set -/code> is set +/code> (note the plus sign).

So set +e will undo set -e, and set +o pipefail will undo set -o pipefail.

set -e ignored in function when invoked in context where exit status is tested?

Test 1

Use set -E (aka set -o errtrace) in addition to set -e if you want the behavior of set -e to apply even inside a function:

set -E -e

foo () (
echo $SHELLOPTS
false
echo set -e failed
)

echo test1:
foo
test $? -ne 0 && echo died

echo
echo test2:
foo && echo died

Note, however, that triggers an exit, not a return, should the function fail. Thus, the output of this is something akin to:

test1:
braceexpand:errexit:errtrace:hashall:interactive-comments:xtrace

...with no further content, as the exit occurs immediately on the false.

Test 2

As for foo && echo died, because the exit status for foo is tested, the flag to disable set -e is enabled during its execution, so it's expected, defined behavior for this flag to have no effect.

Advice

The behavior of set -e is not intuitive. Before depending on it, be sure you fully understand all the examples of behavior given in BashFAQ #105, and consider also reading through the excellent fvue writeup of error handling in bash.

What does set -e mean in a bash script?

From help set :

  -e  Exit immediately if a command exits with a non-zero status.

But it's considered bad practice by some (bash FAQ and irc freenode #bash FAQ authors). It's recommended to use:

trap 'do_something' ERR

to run do_something function when errors occur.

See http://mywiki.wooledge.org/BashFAQ/105

Can “set -e” be disabled in a script?

@Charles Duffy on another thread answered this. not exit a bash script when one of the sub-script fails

set +e undoes set -e. However, using set -e is a bad idea in general; better to use || exit on individual commands where you want a nonzero exit status to be fatal. (Skip past the parable to the exercises if you're in a hurry). – Charles Duffy



Related Topics



Leave a reply



Submit