exit shell script from a subshell

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 # not 77, exit only this subshell
    )
    echo ici
    exit 77 # exit all subshells
  )
  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]"


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.


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.