Search code examples
bash

Why does Bash script command "set -E" prevent me returning 1 from a function?


I'm writing a Bash script in which I issue the "set -E" command, and use traps to detect errors. The "set -E" command causes the ERR trap to be inherited by shell functions. This is a must for me since I'm also using OpenSSL commands which trigger traps that are undetectable by the shell by default.

All this was working fine, until I decided to ask the user a question, and return a value from a function indicating the answer: 0 for yes, 1 for no. When I return 1 from the function, the shell detects that as an ERR trap and executes the trap function. I don't want that to happen.

The code below is a bare-bones example. When I answer "no" (function returns 1), the ERR trap function gets executed and displays "Test.sh: error 1 occurred on line 37".

When I comment out the "set -E" command, this problem goes away, but then the shell can't detect OpenSSL command failures.

How can I return 1 from the function without this problem occurring? Thanks.

#!/bin/bash

ScriptName=$(basename "$0")

#set -E # causes ERR trap to be inherited by shell functions

trap 'SigintHandler'         SIGINT
trap 'ErrHandler $? $LINENO' ERR

function main() {
   Confirm "OK to delete?"
}

function Confirm() {
   question="$1"
   while true; do
      read -p "$question [y/n]: " yn
      case $yn in
         [Yy]*) return 0;;  
         [Nn]*) return 1;;
      esac
   done
}

function SigintHandler() {
   printf "%s: aborted by user\n" "$ScriptName"
   exit 1
}

function ErrHandler() {
   errNum="$1"
   lineNum="$2"
   printf "%s: error %s occurred on line %s\n" "$ScriptName" "$errNum" "$lineNum"
   exit 1
}

main "$@"

Solution

  • The ERR trap is executed whenever a command or function returns a non-zero exit status, since that's how errors are indicated to the shell.

    However, it's not executed when the command is used as a condition in if, while, or until, or part of an && or || list. So you need to test the result of the call to Confirm, e.g.

    function main() {
        if Confirm "OK to delete?"
        then
            rm -- "$@"
        fi
    }