What is the difference between the return
and exit
statement in Bash functions with respect to exit codes?

- 10,737
- 9
- 38
- 58
-
75Protip: type `help
` in your shell to get info on what a shell builtin will do. In your case `help return` and `help exit` – SiegeX Dec 12 '10 at 01:31 -
5Protip #2: type `type
` in your shell to get info whether it's a Bash built-in or not. – Artfaith Mar 08 '21 at 02:52 -
1If you want to exit a script both either sourced or not, you can do: `return 2> /dev/null | exit`. It will first try returning and, in case it can't, it won't display any error and will use exit. – André Willik Valenti Apr 21 '21 at 22:48
-
1Protip #4: `man exit` – Timo Sep 26 '21 at 13:25
-
1Put `help () {sh -c "help $*"}` in your .zshenv – Nick Podratz Feb 02 '22 at 11:37
11 Answers
From man bash
on return [n]
;
Causes a function to stop executing and return the value specified by n to its caller. If n is omitted, the return status is that of the last command executed in the function body.
... on exit [n]
:
Cause the shell to exit with a status of n. If n is omitted, the exit status is that of the last command executed. A trap on EXIT is executed before the shell terminates.
EDIT:
As per your edit of the question, regarding exit codes, return
has nothing to do with exit codes. Exit codes are intended for applications/scripts, not functions. So in this regard, the only keyword that sets the exit code of the script (the one that can be caught by the calling program using the $?
shell variable) is exit
.
EDIT 2:
My last statement referring exit
is causing some comments. It was made to differentiate return
and exit
for the understanding of the OP, and in fact, at any given point of a program/shell script, exit
is the only way of ending the script with an exit code to the calling process.
Every command executed in the shell produces a local "exit code": it sets the $?
variable to that code, and can be used with if
, &&
and other operators to conditionally execute other commands.
These exit codes (and the value of the $?
variable) are reset by each command execution.
Incidentally, the exit code of the last command executed by the script is used as the exit code of the script itself as seen by the calling process.
Finally, functions, when called, act as shell commands with respect to exit codes. The exit code of the function (within the function) is set by using return
. So when in a function return 0
is run, the function execution terminates, giving an exit code of 0.

- 19
- 4

- 28,636
- 4
- 59
- 87
-
-
10Not exactly. It always return a value from the current shell. It doesn't matter if you are inside a function or not. – Diego Sevilla Dec 12 '10 at 01:36
-
13Comment on your edit: I may be confusing return values and exit codes, but `func(){ return 50; };func;echo $?` echoes 50. So the `$?` shell variable doesn't seem to be limited to `exit`. – lecodesportif Dec 12 '10 at 01:53
-
8"`$?` Expands to the exit status of the most recently executed foreground pipeline." That exit may be from the shell in the form of a call to `exit` (or hitting the end of the script) or in the form of a call to `return` within a function. – SiegeX Dec 12 '10 at 01:58
-
13@lecodesportif: The `$?` **of the current process/script** is limited either to `exit` or to the result of the last command executed by this script. So, if your last script line is the call to that function, and that function returns 50, yes, the `$?` that you produce *to the process that called you* is 50. However, that doesn't have to do with the `return`, because this is restricted to the current script. It happens to be returned only if this function call is the last sentence of the script. `exit`, however, always finish the script and return that value as `$?` **to the calling process**. – Diego Sevilla Dec 12 '10 at 10:05
-
13-1 for confusing me with the line "`return` has nothing to do with exit codes." Experimentation tells me that there is no functional difference between the return code of a function and the exit code of a script. – Jacklynn Jun 23 '15 at 15:06
-
Jack, this is plain wrong. Of course return has nothing to do with exit codes. – Diego Sevilla Jun 23 '15 at 16:24
-
5@DiegoSevilla I agree, your statement is confusing. According to the docs: http://tldp.org/LDP/abs/html/complexfunct.html#RETURNREF. In particular: "Terminates a function. A return command [1] optionally takes an integer argument, which is returned to the calling script as the "exit status" of the function, and this exit status is assigned to the variable $?." So while you're absolutely right that `return` will only set the exit code for the *script* if the function is the last command to be executed in the script, the documentation clearly defines "exit status" to be defined for functions. – Dathan Aug 18 '15 at 06:44
-
If anyone else got here from a random issue, you may want to check out `set -o pipefail` - that's what I needed in my script. – Blaskovicz Dec 16 '15 at 16:51
-
3This is simply false. Shell functions *do* set `$?` within the context of the enclosing script, and if a call to a shell function is the last operation in a script, then the function's return value will be the exit status of the script. – Charles Duffy Jan 22 '16 at 23:41
-
3-1 for "return has nothing to do with exit codes" - No no no! You can return exit codes from functions, and those functions and their exit codes can be used in command lists just like applications. Consider: `do_junk() { ls /tmp/bleedledorf 2>/dev/null; } ; do_junk && echo found` will return nothing. `do_junk() { ls /tmp/bleedledorf 2>/dev/null; return 0; }; do_junk && echo found` will return *found* – Mike S May 27 '16 at 20:43
-
*"[exit causes] the shell to exit"* or not, if you used a subshell. I had forgotten I started a subshell and got to this page because I was starting to question my sanity after the script continued despite an `exit`! – Luc Apr 01 '20 at 15:05
-
I guess the debate is based on @DiegoSevilla thinks a _function_ does not have exit code nor exit status at all, while only a _script_ can have exit code. I see his point but I do not agree. IMO both functions and scripts have exit codes. A function is a script also. Hmm... this may be a philosophy point of view differences, which (seems) does not affect coding at all. – midnite May 06 '22 at 19:19
return
will cause the current function to go out of scope, while exit
will cause the script to end at the point where it is called. Here is a sample program to help explain this:
#!/bin/bash
retfunc()
{
echo "this is retfunc()"
return 1
}
exitfunc()
{
echo "this is exitfunc()"
exit 1
}
retfunc
echo "We are still here"
exitfunc
echo "We will never see this"
Output
$ ./test.sh
this is retfunc()
We are still here
this is exitfunc()

- 8,287
- 7
- 55
- 80

- 135,741
- 24
- 144
- 154
-
26
-
54Note that this function will NOT print "We are still here" if you add "set -e" before the call to "retfunc". – Michael Apr 30 '12 at 23:12
-
7However, `echo fnord | while read x; do exitfunc; done; echo "still here"` will print "still here". It seems that only the `while` sub-shell is exited in this scenario. – tripleee Dec 11 '13 at 09:30
-
An approximate workaround is `done || exit $?` but that is ugly and not precisely equivalent. – tripleee Dec 11 '13 at 09:44
-
@tripleee right, `exit` will terminate the current shell. In your example the pipe created a subshell of which the while loop will run. To avoid the subshell and get the same functionality you can use process substitution `while read x; do exitfunc; done < <(echo fnord); echo "still here"` – SiegeX Dec 13 '13 at 06:32
-
4+1 It might be useful to add: ``` `return` will cause the current function **or sourced script** to go out of scope```. – Nov 22 '16 at 19:40
-
I wonder if 'scope' is even the correct term in this context. I mean bash/sh is known for having all functions and variables in the global scope, as functions do not have a separate scope, and the only thing that creates something like a scope are sub-shells. – JepZ Nov 07 '18 at 14:23
-
3Note that, in the above example, if you are running with `set -e` so that the script exits on the first error, it will exit after the first function call returns a non-zero value. – Scott Smith Aug 24 '20 at 16:15
-
Regarding to @tripleee example, it is not `while` creating a sub-shell. But as @SiegeX mentioned, it is **the pipe created a subshell**. Consider this `echo 'a' | exit 1; echo 'pipe created a sub-shell'; while true; do echo 'b'; exit 1; done; echo 'Never reach'`. It prints `pipe created a sub-shell` then `b`. – midnite May 06 '22 at 20:22
-
-
@midnite I'm not @IsaaC but I guess what they are trying to say is that `return` outside a function will terminate the `source` if the current script file is being sourced. – tripleee May 07 '22 at 07:13
-
@midnite The use of scope started with the OP for this answer. The point I tried to convey is that **sourced scripts** could also be stopped with `return` (not only functions). – May 08 '22 at 06:53
I don't think anyone has really fully answered the question because they don't describe how the two are used. OK, I think we know that exit kills the script, wherever it is called and you can assign a status to it as well such as exit or exit 0 or exit 7 and so forth. This can be used to determine how the script was forced to stop if called by another script, etc. Enough on exit.
return, when called, will return the value specified to indicate the function's behavior, usually a 1 or a 0. For example:
#!/bin/bash
isdirectory() {
if [ -d "$1" ]
then
return 0
else
return 1
fi
echo "you will not see anything after the return like this text"
}
Check like this:
if isdirectory $1; then echo "is directory"; else echo "not a directory"; fi
Or like this:
isdirectory || echo "not a directory"
In this example, the test can be used to indicate if the directory was found. Notice that anything after the return will not be executed in the function. 0 is true, but false is 1 in the shell, different from other programming languages.
For more information on functions: Returning Values from Bash Functions
Note: The isdirectory function is for instructional purposes only. This should not be how you perform such an option in a real script.*

- 30,738
- 21
- 105
- 131

- 6,716
- 5
- 55
- 62
-
3Or just use `test -d $1` to achieve the same result. Never do `if
return else return`. ` – erikbstack May 21 '15 at 12:00` alone will do the same thing in all languages I know at least. -
6To be even more explicit about what erik is saying: `isdirectory() { [ -d "$1" ]; }` will behave precisely the same as what you have here: The default return value of a shell function, whether by reaching the end of its code or by a `return` with no arguments, is that of the most recent command. – Charles Duffy Jan 22 '16 at 23:39
-
16The other commenters here are criticizing the style of Mike Q's example, when really he is talking about the behavior of the `return`statement. It is true that his example is simplistic and not to be used in production. But it's simple, so it does accomplishes his task just fine. Nothing wrong with it. – Mike S May 27 '16 at 20:48
-
1Thanks Mike S, yeah I agree that the simplest example best explains exit vs return. The other comments are certainly valid, and should be considered for more advanced bash coders ;-) – Mike Q Oct 13 '16 at 13:46
-
@erikbwork Please remove your comment or edit it if you can, the point here is to explain return not the best way to test for a directory. – Mike Q Mar 10 '18 at 16:36
-
1@erikbwork Well this is common practice in most learning materials. As a compromise I added a disclaimer in the post per your opinion. – Mike Q Mar 19 '18 at 13:54
-
1Some might say it's not exactly related to the question, *but it related to and answered the problem I had that led me to find this Question.* :-) – Jesse Jul 01 '19 at 07:11
Remember, functions are internal to a script and normally return from whence they were called by using the return statement. Calling an external script is another matter entirely, and scripts usually terminate with an exit statement.
The difference "between the return and exit statement in Bash functions with respect to exit codes" is very small. Both return a status, not values per se. A status of zero indicates success, while any other status (1 to 255) indicates a failure. The return statement will return to the script from where it was called, while the exit statement will end the entire script from wherever it is encountered.
return 0 # Returns to where the function was called. $? contains 0 (success).
return 1 # Returns to where the function was called. $? contains 1 (failure).
exit 0 # Exits the script completely. $? contains 0 (success).
exit 1 # Exits the script completely. $? contains 1 (failure).
If your function simply ends without a return statement, the status of the last command executed is returned as the status code (and will be placed in $?
).
Remember, return and exit give back a status code from 0 to 255, available in $?
. You cannot stuff anything else into a status code (e.g., return "cat"); it will not work. But, a script can pass back 255 different reasons for failure by using status codes.
You can set variables contained in the calling script, or echo results in the function and use command substitution in the calling script; but the purpose of return and exit are to pass status codes, not values or computation results as one might expect in a programming language like C.

- 30,738
- 21
- 105
- 131

- 431
- 4
- 3
Sometimes, you run a script using .
or source
.
. a.sh
If you include an exit
in the a.sh
, it will not just terminate the script, but end your shell session.
If you include a return
in the a.sh
, it simply stops processing the script.
-
6But when I just run a.sh I get an error `return: can only 'return' from a function or sourced script`, which makes it unsuitable for a general script. – Peter - Reinstate Monica Jun 21 '17 at 11:53
-
1At the top level in a script, neither is suitable in `all` situations. Using `.` or `source` runs the script in the current shell, rather than spawning a sub-shell. The script has to _know_ how it is to be used. Woe to the user who does it opposite. Personally, I recommend reading scripts before running them the first time. – Jesse Chisholm Jun 26 '18 at 20:13
-
11An awesome trick I came across is to use a `trap` function for `ERR EXIT` and then first save the exit code of a failed command `errCode=$?` and then exit the script (sourced or not) with `return $errCode || exit $errCode` where the `||` means "if I can't return because I wasn't sourced, just exit instead". – dragon788 Aug 30 '18 at 20:19
-
exit
terminates the current process; with or without an exit code, consider this a system more than a program function. Note that when sourcing,exit
will end the shell. However, when running, it will justexit
the script.return
from a function go back to the instruction after the call, with or without a return code.return
is optional and it's implicit at the end of the function.return
can only be used inside a function.
I want to add that while being sourced, it's not easy to exit
the script from within a function without killing the shell. I think, an example is better on a 'test' script:
#!/bin/bash
function die(){
echo ${1:=Something terrible wrong happen}
#... clean your trash
exit 1
}
[ -f /whatever/ ] || die "whatever is not available"
# Now we can proceed
echo "continue"
doing the following:
user$ ./test
Whatever is not available
user$
test
-and- the shell will close.
user$ . ./test
Whatever is not available
Only test
will finish and the prompt will show.
The solution is to enclose the potentially procedure in (
and )
:
#!/bin/bash
function die(){
echo $(1:=Something terrible wrong happen)
#... Clean your trash
exit 1
}
( # Added
[ -f /whatever/ ] || die "whatever is not available"
# Now we can proceed
echo "continue"
) # Added
Now, in both cases only test
will exit.

- 30,738
- 21
- 105
- 131

- 1,247
- 15
- 28
-
Adding the `(` and `)` puts that block in a sub-shell, effectively un-doing the `.` (source) command as if you had run the test script normally, which is in a sub-shell. IOf the script is not run with `.` or `source` then you effectively have 2 sub-shells. – Jesse Chisholm Jun 26 '18 at 20:19
The OP's question: What is the difference between the return and exit statement in BASH functions with respect to exit codes?
Firstly, some clarification is required:
A (return|exit) statement is not required to terminate execution of a (function|shell). A (function|shell) will terminate when it reaches the end of its code list, even with no (return|exit) statement.
A (return|exit) statement is not required to pass a value back from a terminated (function|shell). Every process has a built-in variable
$?
which always has a numeric value. It is a special variable that cannot be set like "?=1", but it is set only in special ways (see below *).The value of $? after the last command to be executed in the (called function | sub shell) is the value that is passed back to the (function caller | parent shell). That is true whether the last command executed is ("return [n]"| "exit [n]") or plain ("return" or something else which happens to be the last command in the called function's code.
In the above bullet list, choose from "(x|y)" either always the first item or always the second item to get statements about functions and return, or shells and exit, respectively.
What is clear is that they both share common usage of the special variable $?
to pass values upwards after they terminate.
* Now for the special ways that $?
can be set:
- When a called function terminates and returns to its caller then $? in the caller will be equal to the final value of
$?
in the terminated function. - When a parent shell implicitly or explicitly waits on a single sub shell and is released by termination of that sub shell, then
$?
in the parent shell will be equal to the final value of$?
in the terminated sub shell. - Some built-in functions can modify
$?
depending upon their result. But some don't. - Built-in functions "return" and "exit", when followed by a numerical argument both set
$?
with their argument, and terminate execution.
It is worth noting that $?
can be assigned a value by calling exit in a sub shell, like this:
# (exit 259)
# echo $?
3

- 2,199
- 20
- 35
-
5In case some missed it, `exit 259` echos as `3` because the final exit value is a single byte. `259 % 256 = 3` – Jesse Chisholm Jun 26 '18 at 20:23
-
1What do you mean by the sentence near *"both `$?` with argument"* (it seems incomprehensible)? Perhaps rephrase? Please respond by [editing your answer](https://stackoverflow.com/posts/49391514/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen Feb 27 '21 at 17:56
-
1I'm guessing the sentence is trying to say that the argument to `exit` or `return` is stored in `$?`. – tripleee May 07 '22 at 07:18
In simple words (mainly for newbie in coding), we can say,
`return`: exits the function,
`exit()`: exits the program (called as process while running)
Also if you observed, this is very basic, but...,
`return`: is the keyword
`exit()`: is the function

- 30,738
- 21
- 105
- 131

- 829
- 9
- 23
-
4In a bash script, `exit` is no more or less a function than `return`. They are built-in commands. They are not even reserved words. – Peter - Reinstate Monica Jun 21 '17 at 11:01
If you convert a Bash script into a function, you typically replace exit N
with return N
. The code that calls the function will treat the return value the same as it would an exit code from a subprocess.
Using exit
inside the function will force the entire script to end.

- 30,738
- 21
- 105
- 131

- 1,002
- 1
- 14
- 19
Adding an actionable aspect to a few of the other answers:
Both can give exit codes - default or defined by the function, and the only 'default' is zero for success for both exit and return. Any status can have a custom number 0-255, including for success.
Return is used often for interactive scripts that run in the current shell, called with . script.sh
for example, and just returns you to your calling shell. The return code is then accessible to the calling shell - $?
gives you the defined return status.
Exit in this case also closes your shell (including SSH connections, if that's how you're working).
Exit is necessary if the script is executable and called from another script or shell and runs in a subshell. The exit codes then are accessible to the calling shell - return would give an error in this case.

- 30,738
- 21
- 105
- 131

- 29
- 1
- 1
- 6
First of all, return
is a keyword and exit
is a function.
That said, here's a simplest of explanations.
return
It returns a value from a function.
exit
It exits out of or abandons the current shell.

- 30,738
- 21
- 105
- 131

- 33,440
- 5
- 74
- 56
-
Not really! You are logically wrong. Exit is a function while `return` is a keyword. Return is much more than just exit codes which is why the comparison isn't fair. – Ahmad Awais Jan 20 '17 at 20:00
-
I have edittled it to make the point more clear which I was trying to make. Thanks for helping me do that. – Ahmad Awais Jan 21 '17 at 05:00
-
5Neither `exit` nor `return` are "keywords", or, as the bash manual calls them, "reserved words". Neither one is a "function" either, in the sense of a bash function. Both are **builtin commands,** in bash lingo. (There *is* a C standard library function called `exit()`, and the C programming language has a reserved word `return`, but those should not be confused with the bash commands, even though their semantics are curiously similar.) – Peter - Reinstate Monica Jun 21 '17 at 12:01