I have default bash v4.4.12 set up on Debian:
$ bash --version
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)
I prefer to use these options in my scripts:
set -o pipefail
set -o errexit
set -o nounset
It make stop a script on non-zero result in pipe-commands (pipefail), execute exit (errexit), and validate unset variables (nounset).
I have test script:
set -o pipefail
set -o errexit
set -o nounset
set -o xtrace
return_1() { return 22; }
test_1 () {
  return_1;
  echo 'after';
}
success_1() {
  echo success
}
if [ "${1:-}" == 1 ]; then
  # make "return 1" in the root level
  return_1
fi
if [ "${1:-}" == 2 ]; then
  # run test_1, we will get "return 1" within a function
  test_1
fi
if [ "${1:-}" == 3 ]; then
  # run test_1 and success_1 in chain
  # success_1 MUST NOT be ran because test_1 makes non-zero status
  # in fact, success_1 will be ran =(
  test_1 && success_1
fi
Testing.
$ bash /test.sh 1; echo "status: ${?}"
+ '[' 1 == 1 ']'
+ return_1
+ return 22
status: 22
Works as expected.
$ bash /test.sh 2; echo "status: ${?}"
+ '[' 2 == 1 ']'
+ '[' 2 == 2 ']'
+ test_1
+ return_1
+ return 22
status: 22
Everything is right. The line "echo 'after';" haven't called.
$ bash /test.sh 3; echo "status: ${?}"
+ '[' 3 == 1 ']'
+ '[' 3 == 2 ']'
+ '[' 3 == 3 ']'
+ test_1
+ return_1
+ return 22
+ echo after
after
+ success_1
+ echo success
success
status: 0
Completely NOT right. :( 1. The line "echo 'after';" have called. 2. The function "success_1" have called as well.
Really, what's going on in this case?
UPD Manual refferences.
 
    