Like filesystem scripts or programs, Bash functions can have exit values. These are integer values normally used to describe how well the function did its job, often for use by the calling shell or program to decide what to do next after the function completes. In the case of functions, we will call these return values for clarity, as they use the return keyword rather than exit.
Here's an example of a simple pair of functions, succeed and fail; rather like true and false, they always return 0 and 1, respectively:
bash$ succeed() { return 0 ; } bash$ fail() { return 1 ; }
As observed in Chapter 2, Bash Command Structure, we can test these using the special $? parameter:
bash$ succeed;echo $? 0 bash$ fail;echo $? 1
A function does not have to have a return statement. If you leave it out, or use return without specifying a number afterward, the function's return value will be the exit value of the last command it ran. This means we could write succeed() and fail() like this instead, using the true and false commands:
bash$ succeed() { true ; } bash$ fail() { false ; }
Be careful not to confuse return and exit. The former is for functions; the latter is for scripts. If you use exit in a function, the shell itself will exit, not just the function. This can be an unpleasant surprise when you're in the middle of some work!
An early return can sometimes be a good way to stop processing a function due to usage errors. This is sometimes referred to as short-circuiting. In our mkcd example, we know we can't accept more than one argument, because we can't change into more than one directory. We could add a few lines to the function for a full definition, like so:
mkcd() { if (($# != 1)) ; then printf >&2 'Need exactly one argument\n' return 1 fi mkdir -- "$1" && cd -- "$1" }
In this example, the function tests whether $# (the number of arguments) is equal to 1 before proceeding. If it's not exactly 1, the function prints an error message and returns 1, to represent having failed to do what it was asked, and the mkdir and cd commands are never run.