1

I'm trying to use trap ERR in my scripts. But:

function hmmm() {
    trap 'exit 10' ERR
    echo 12>/SOME/NONEXISTING/FILE
    # some commands that must not be done if previous has failed
    echo "THAT MUST NOT BE PRINTED" >&2
    return 5
}   

echo ok1
a=$(hmmm) || status="$?"
echo "function returns: $status"

Prints

ok1
test2.sh: line 3: /SOME/NONEXISTING/FILE: No such file or directory
THAT MUST NOT BE PRINTED
function returns: 5 

The same behavior with any combination of set -e, set -E, trap on top level etc. I always need to handle return code of function - so, as I undertand, I can't use trap ERR in my scripts at all - I willn't ever working. Am I right, or there is working method to enable trap ERR inside functions, subshells and sourced libraries and keep constructions like

a=$( ...somecode ... ) || result="$?"

working? Or, that more important, in example above make bash exit on error inside function ALWAYS, not depending on calling method.

Added: In fact, I want to know is there any working way to BE SURE that errors are trapped inside functions, subshells and sourced code. Because my functions and libraries can be used by other peoples - so, I can't control how this functions are called, and, to be honest, even if I can - I will never use some behavior inside function, that can be accidentally and silently changed from outside.

Malamut
  • 39
  • 3

1 Answers1

1

trap isn't executed since it's a part of ||.

Change:

a=$(hmmm) || status="$?"

to:

a=$(hmmm)
status="$?"

From bash manual:

The ERR trap is not executed if the failed command is part of the command list immediately following a while or until keyword, part of the test in an if statement, part of a 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 using !. These are the same conditions obeyed by the errexit (-e) option.

P.P
  • 117,907
  • 20
  • 175
  • 238
  • Failed command (`echo 12>...`) IS NOT a part of `||` or smth from manual. Moreover, you can't use `a=$(hmmm); status="$?"` because you of course want trap ERR on top level too, and if `hmmm` will return something except 0 - your script will die. – Malamut Apr 19 '20 at 07:07
  • The execution of `hmmm` *is* a part of the failed command (as the quote says). The whole function `hmmm` is "command". That's how trap ERR works. If you want to be able to handle, testing non-zero return with an `if` statement may be more suitable. – P.P Apr 19 '20 at 12:07
  • I see that it works in such manner. But no, function body is not a part of command ||. Only the call of function is. For example, it can be `a=$(/some/external/bash/script.sh) || status="$?"` - content of script.sh will not be a part of ||. Moreover, there is `set -E` command in bash. For what it exists, if it can't work at all, because trap ERR inside functions can work only in synthetic cases and will never work in real scripts, and so, must never be used? And `set -e` must never be used too, because it can't guarantee that failed command will break a script? – Malamut Apr 20 '20 at 12:43