5

I'm puzzled by bash (and dash) behavior when -e option is set.

Simple example:

#!/bin/bash -e

func() {
    false && true
}

false && true

echo "1"

func

echo "2"

outputs:

1

expected output:

1
2

While first occurrence works as expected, second occurrence (inside function) leads to immediate exit. I searched documentation but was unable to find explanation to such different behavior. Is there any rationale behind this, or is this bug? I tested this in bash and dash with same results.

According to bash manpage:

-e Exit immediately if a pipeline (which may consist of a single simple command), a list, or a compound command (see SHELL GRAMMAR above), exits with a non-zero status. The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test following the if or elif reserved words, part of any command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command's return value is being inverted with !. 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. A trap on ERR, if set, is executed before the shell exits. This option applies to the shell environment and each subshell environment separately (see COMMAND EXECUTION ENVIRONMENT above), and may cause subshells to exit before executing all the commands in the subshell.

If a compound command or shell function executes in a context where -e is being ignored, none of the commands executed within the compound command or function body will be affected by the -e setting, even if -e is set and a command returns a failure status. If a compound command or shell function sets -e while executing in a context where -e is ignored, that setting will not have any effect until the compound command or the command containing the function call completes.

2

2 Answers 2

8

The script terminates upon returning from func, since its exit status is non-zero. The script is not terminating inside func.

The false && true list is unaffected by -e, and the script does not terminate from it, not in the main part of the script and not in the function.

However, the false in the function sets the function's exit status to non-zero, so when the function returns, the shell terminates.

Your script may be simplified into

#!/bin/bash -e

false && true

echo "1"

false

echo "2"

You may also want to test returning zero from your function to convince yourself that the false && true list in the function is not terminating the script:

#!/bin/bash -e

func() {
    false && true
    return 0
}

false && true

echo "1"

func

echo "2"

Running this outputs

1
2
2
  • Thank, I really did not realized it. I guess it is important to sanitize function returns.
    – ZiGi
    Commented Apr 28, 2021 at 20:30
  • 1
    @ZiGi I would rather remove the -e and add proper failure checks :-)
    – Kusalananda
    Commented Apr 28, 2021 at 20:36
1

Not directly relevant as you're not asking about traps, but...

ERR traps and set -E vs set -e

Note that set -E does not include set -e. Given this script that has an error in a function:

$ cat trap_test.sh
#!/usr/bin/env bash
trap 'echo "Error on line $LINENO. Exit code: $?" >&2' ERR
myfunc() {
    noSuchCommand
    echo OK
}
myfunc

then we can examine the combinations of -E and -e

  1. neither specified: no trap, no early exit
    $ bash trap_test.sh; echo "exit status: $?"
    trap_test.sh: line 6: noSuchCommand: command not found
    OK
    exit status: 0
    
  2. -e: early exit, no trap from the function
    $ bash -e trap_test.sh; echo "exit status: $?"
    trap_test.sh: line 6: noSuchCommand: command not found
    exit status: 127
    
  3. -E, trap fired from error in function
    $ bash -E trap_test.sh; echo "exit status: $?"
    trap_test.sh: line 6: noSuchCommand: command not found
    Error on line 6. Exit code: 127
    OK
    exit status: 0
    
  4. both early exit and trap/
    $ bash -eE trap_test.sh; echo "exit status: $?"
    trap_test.sh: line 6: noSuchCommand: command not found
    Error on line 6. Exit code: 127
    exit status: 127
    

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .