I want my sourced script to run with nounset, pipefail etc. I want to restore the options to their previous values when it returns.
I want an errexit-like behavior inside the sourced script too. It's not exactly errexit because I want the sourced script to return on error, but don't cause the caller to exit.
This is what I came up with, it seems to work for the simple examples I tried.
One problem I see is that this will not work with actual errexit if somebody tries to use it in the sourced script.
Another problem is that apparently nounset will not trigger an ERR trap at all.
trap " err_status=\$? if ! [[ \${FUNCNAME[1]-} ]]; then echo 'Resetting shell options' >&2 trap - RETURN ERR $(shopt -po) return \$err_status else echo 'Returning with status' \$err_status >&2 return \$err_status fi " ERR trap " echo 'Resetting shell options' >&2 trap - RETURN ERR $(shopt -po) " RETURN set -o errtrace -o nounset -o pipefail +o history fail() { echo "About to fail" false echo "This will not print" } echo "Calling" "${1-fail}" echo "After call" Results:
$ . demotrap.sh false; echo $? Calling Resetting shell options 1 $ . demotrap.sh true; echo $? Calling After call Resetting shell options 0 $ . demotrap.sh fail; echo $? Calling About to fail Returning with status 1 Resetting shell options 1
. <( ./script-outputing-shell-statements)hack, but it awkward to use interactively.. <(foo)orexec "$(foo)". Yes, either is awkward to write by hand, but you can wrap that part in a function (or a sourced script) and do the actual logic in an independent scripteval "$(whatever)". Well, they do mostly the same, but the process substitution<(cmd)is not POSIX, so that wouldn't work if you ever tried that with a more limited shell.eval "$(whatever)"would be more widely supported. Probably doesn't matter much, since people likely use either Bash or zsh as their interactive shell (unless they use something non-POSIX-like, and the neither<()or$()might work).