3

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.

Aquarius Power
  • 4,099
  • 5
  • 38
  • 56

2 Answers2

4

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.

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
  • It was right in the first sentence, though the `ret=` thing might be a little much - if I'm one to talk. I just mean that `return/exit` etc automatically return `$?` so it's far more efficient to simply detect failure: `(false) || return` will always return `false`'s parent shell's `$?`. – mikeserv Jul 24 '14 at 03:24
  • I am currently checking if some approach could be done with traps ERR, RETURN and DEBUG, but I am still failing horribly :), as I already use DEBUG one for other thing, I will focus on ERR and RETURN. – Aquarius Power Jul 24 '14 at 18:18
0

My script was badly coded, but it can be fixed:

Look at the 1st, 2nd and 3rd comments:

  • 1st A TRAP ERR IS REQUIRED
  • 2rd errors that you take care wont be trapped! do not use if ! ... will prevent getting return value with $?
  • 3nd DO NOT ECHO DIRECTLY, use a intermediary variable so the error can be cautch

tstNounset.sh:

#!/bin/bash
trap 'ErrorHappened;exit 1' ERR #1st A TRAP ERR IS REQUIRED

set -x 
set -o nounset;set -u

#echo `echo $str`
nRet=0;if strA="`echo $str`";then : ;else nRet=$?;echo "Err$nRet";fi #2rd errors that you take care wont be trapped! do not use `if ! ...` will prevent getting return value with $?
echo "0 - should not reach here?"
strA="`echo $str`";echo "$strA" #3nd DO NOT ECHO DIRECTLY, use a intermediary variable so the error can be cautch
echo "1 - should not reach here?"
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 - doesnt reach here."
Aquarius Power
  • 4,099
  • 5
  • 38
  • 56