TIL

Bash set -e, Compound Commands, and &&

I ran into a sneaky bash issue today that left me scratching my head. A script with set -e was continuing to run even after a command in the script failed.

Turns out this is documented behavior in bash, not a bug. For loops are compound commands and according to the Bash manual:

The shell does not exit if the command that fails is ... part of any command executed in a && or || list except the command following the final && ... If a compound command other than a subshell returns a non-zero status because a command failed while -e was being ignored, the shell does not exit.

For a for loop,

The return status is the exit status of the last command that executes.

Let's put this to the test with a simple script:

#!/bin/bash
set -e

for x in {1..3}; do
  if [ "$x" = 2 ]; then
    echo "fail"
    false  # the script does not exit here
  fi
  echo "$x"
done && \
echo "done"  # this runs!

Output:

1
fail
2
3
done

One of the many idiosyncracies of our old friend bash.