14

Does set -e behave differently here

set -e;

function foo {

}

vs.

function foo {
  set -e;

}

does set -e belong inside functions? Does set -e declared outside of functions, affect "nested" functions inside a shell file? What about the inverse? Should we call local set -e lol?

  • 4
    My advise (and many's): don't use set -e in a script complex enough as to need functions. Do proper error handling instead. – Stéphane Chazelas Nov 18 '17 at 11:27
  • @StéphaneChazelas set -e was never supposed to be a replacement for error handling but a safeguard to avoid catastrophic failures if handling error has been overlooked and continuing executing a script after a command failed can easily have crazy consequences, like massive loss of data. – Mecki Jan 05 '24 at 17:33

2 Answers2

13

Note: the statements here apply to Bash version 4.0.35 and up. Implementations of set -e vary wildly among different shells/versions. Follow Stéphane's advice and don't use set -e.

man bash in the Shell Builtin Commands/set section explains things pretty well though the text is a little dense and requires a bit of focus. To your specific questions the answers are:

  • Does set -e behave different here...vs.. - Depends on what you mean by "differently" but I suspect you'd consider the answer "no"...there are no tricky scoping rules. It acts quite linearlly.
  • Does set -e belong inside functions? - Perfectly valid.
  • Does set -e declared outside of functions, affect "nested" functions inside a shell file? - Yes
  • What about the inverse? - set -e in a function and then encounter a non-zero status after return? Yes, this will exit.
B Layer
  • 5,171
  • 2
    There are complex rules that differ between versions. See http://mywiki.wooledge.org/BashFAQ/105 and linked pages for details. Best to stay away from set -e. – Stéphane Chazelas Nov 18 '17 at 11:35
  • will set -e inside a function affect the whole shell? Because this question - https://unix.stackexchange.com/questions/407385/any-command-in-my-terminal-that-exits-with-non-zero-code-closes-my-terminal-wind – Alexander Mills Nov 29 '17 at 01:18
  • Yes, that's what the fourth bullet indicates. Functions aren't isolated environments (discounting local vars). (If you ever use set -x to debug and put it in a function you'll see this in action.) Again, I've only tested with Bash 4.4... earlier (much earlier?) versions may have different behavior. – B Layer Nov 29 '17 at 03:55
  • @StéphaneChazelas But that's only because bash is a broken mess. The POSIX standard is very clear on this and demands that the the flag does propagate to subshells. Here's an example from the POSIX standard: set -e; (false; echo one) | cat; echo two In this code the standard demands that one must not be printed and the subshell must exit. Any shell showing different behavior is not POSIX conform. – Mecki Jan 05 '24 at 17:30
-2

Solution to avoid any headaches:

function foo {
  (
       set -e;
  )
}

(Just use a subshell). Sometimes to make it both confusing and pretty, I do this:

 function foo {(
      set -e;
      # the rest goes here
  )}
  • Actually {( ... )} is not required. If you want a function to run in a subshell, just declare it as foo( ) ( ... code ... ). This is perfectly valid according to POSIX standard. Function bodies can either be enclosed in { ... } or ( ... ), depending if you want to run it in the same shell or in a subshell. – Mecki Jan 05 '24 at 14:14