5

Note: this is not a duplicate of In bash, is there an equivalent of die "error msg" , as illustrated at the end of this post.

Consider the shell function

foo () {
    echo "testing..." 1>&2
    return 1
    echo "should never reach this point" 1>&2
}

The following shows foo's expected behavior:

% foo || echo $?
testing...
1

I would like to encapsulate the functionality shown in the first two lines of foo in a function die, so that the definition of foo could be reduced to

foo () {
    die 1 "testing..."
    echo "should never reach this point" 1>&2
}

...while still preserving its original behavior.

My interest is primarily zsh, but would also be interested in answers suitable for bash and/or /bin/sh scripts, if they're different.


BTW, this won't work:

die () {
    local exit_code=$1
    shift
    echo "$*" 1>&2
    exit $exit_code
}

If one ran from the command line a version of foo that used this die, the result would be to kill one's current shell (at least this is the result I get when I try something similar). This is why this question is not a duplicate of In bash, is there an equivalent of die "error msg". At any rate, the answer to that other question won't satisfy my requirements here.

Community
  • 1
  • 1
kjo
  • 33,683
  • 52
  • 148
  • 265

2 Answers2

1

Strictly speaking, I don't think what you want is possible. You can't return from a function simply by calling another function. This might be close to what you want, though:

die () {
    echo "${*:2}" 1>&2
    return $1
}

foo () (      # Parentheses, not braces, to enclose the body
    set -e
    die 1 "testing..."
    echo "Shouldn't reach here" 1>&2
)

When die returns with status 1, the set -e causes the current shell to exit. However, the body of foo started a new subshell, so that's what exits, returning control to the shell that called foo. However, there are two glaring problems:

  1. set -e; die... is no shorter than echo...; return 1
  2. Making the body of foo a subshell will prevent any variables set in that function from being visible to the caller.
chepner
  • 497,756
  • 71
  • 530
  • 681
  • The first problem you mention is only an artifact of the toy example; in a real function there are typically several calls to `die`, for which one `set -e` will suffice. The second problem is far more serious, since one of the main advantages of using a function, rather than a shell script, is precisely the fact that functions can modify that current shell's environment. – kjo Apr 04 '13 at 21:25
0

As of zsh 4.3.4, you can use throw/catch syntax. I find it much less problematic than old school 'set -e' or exit for error handling. Just make sure you do "autoload -U throw catch" to get access to them. Check out "man zshcontrib" for the details.

Steve Goranson
  • 329
  • 2
  • 8