Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Consider this snippet:

stop () {
    echo "${1}" 1>&2
    exit 1
}

func () {
    if false; then
        echo "foo"
    else
        stop "something went wrong"
    fi
}

Normally when func is called it will cause the script to terminate, which is the intended behaviour. However, if it's executed in a sub-shell, such as in

result=`func`

it will not exit the script. This means the calling code has to check the exit status of the function every time. Is there a way to avoid this? Is this what set -e is for?

share|improve this question
1  
i want a function "stop" that prints a message to stderr and stops the script, but it doesn't stop when the function that calls stop is executed in a sub-shell, like in the example –  Ernest A C Sep 18 '12 at 16:41
2  
Of course, because it exits from the subshell not the current one. Simply call the function directly: func. –  Herman Torjussen Sep 18 '12 at 16:42
1  
i can't call it directly because it returns a string that has to be stored in a variable –  Ernest A C Sep 18 '12 at 16:53
1  
@ErnestAC Please provide all the details in the original question. The above function does not return a string. –  Herman Torjussen Sep 18 '12 at 17:03
1  
@htor I changed the example –  Ernest A C Sep 18 '12 at 17:29

3 Answers 3

up vote 2 down vote accepted

You could kill the original shell (kill $$) before calling exit, and that'd probably work. But:

  • it seems rather ugly to me
  • it will break if you have a second subshell in there, i.e., use a subshell inside a subshell.

Instead, you could use one of the several ways to pass back a value in the Bash FAQ. Most of them aren't so great, unfortunately. You may just be stuck checking for errors after each function call (-e has a lot of problems). Either that, or switch to Perl.

share|improve this answer
1  
Thanks. I'd rather switch to Python, though. –  Ernest A C Sep 18 '12 at 18:35

You could decide that the exit status 77 for instance means exit any level of subshell, and do

set -E
trap '[ "$?" -ne 77 ] || exit 77' ERR

(echo here; (echo there; (exit 12); echo ici; exit 77);
echo not here); echo not here either

set -E in combination with ERR traps is a bit like an improved version of set -e in that it allows you to define your own error handling.

In zsh, ERR traps are inherited automatically, so you don't need set -E, you can also define traps as TRAPERR() functions, and modify them through $functions[TRAPERR], like functions[TRAPERR]="echo was here; $functions[TRAPERR]"

share|improve this answer
1  
Interesting solution! Clearly more elegant than kill $$. –  Herman Torjussen Sep 19 '12 at 9:23

As an alternative to kill $$, you may also try kill 0, it will work in the case of nested subshells (all callers and side process will receive the signal) … but it's still brutal and ugly.

share|improve this answer
1  
Wouldn't this kill process id 0? –  Ernest A C Sep 18 '12 at 18:35
3  
That'll kill the entire process group. You may hit things you don't want (if for example you've started some things in the background). –  derobert Sep 18 '12 at 19:11
1  
@ErnestAC see the kill(2) manpage, pids ≤0 have special meaning. –  derobert Sep 18 '12 at 19:15

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.