Bash ‘nounset’ on sub-shell/child doesn’t force main script to exit, how to workaround that globally

basherror handling

With this script: tstNounset.sh

#!/bin/bash
set -x 
set -o nounset;set -u

echo `echo $str`
function FUNC1() { echo $str; };export -f FUNC1;bash -c FUNC1
function FUNC2() { set -u;echo $str; };export -f FUNC2;bash -c FUNC2
echo "A - should not reach here?"
echo $str
echo "B - doesn't reach here."

I would like to prevent reaching "A", in a global manner, not requiring to check each variable for it.

Also without using set -e (as I take care of errors and workaround most already, as many also are only warnings).

I thought if there could have some way to detect "unbound variable" happened even from subshell/child, so I could force an exit from that?

I couldn't make things work from How to have a bash script perform a specific action on errors of _each_ command? or How to trigger error using Trap command also. I found this old question too.

Best Answer

Subshells

There is no way for a subshell to kill the whole script. Under the effect of set -u, a subshell has no way to tell its parent “hey, I want you to treat this as a fatal error”. This wouldn't even make sense if set -u was in effect in the subshell but not in its parent. All the subshell can do is return a nonzero exit code. It's up to you to handle that exit code in the parent, either manually or through set -e.

(set -u; …; echo $undefined_variable)
# here $? is nonzero
ret=$?; if [ $ret -ne 0 ]; then exit $ret; fi

Subprocesses

What you've done here is not a subshell: you're launching another program. That other program happens to be bash, which is also the interpreter that's executing the present script, but it's a coincidence. There is absolutely no reason why a setting in a program invoked by bash would cause bash itself to exit.

set +e
bash -c 'do something'
echo "A - should and does reach here"

This is no different than if you'd written perl -e 'use strict; print $barf' — Perl would die and return a nonzero status but that doesn't cause the bash script to exit (except under set -e). Use set -e if you want to exit when a subprocess returns a nonzero return code.

Related Question