I have a Bash script that can either be executed directly or sourced into the current shell. When it finishes, I want it to use `return` if it was sourced and `exit` if it was executed normally.
A common way to detect whether the script is sourced is `(return 0 2>/dev/null)`. That leads to an explicit conditional:
```bash
if (return 0 2>/dev/null); then
return "$exitcode"
else
exit "$exitcode"
fi
```
However, I could also write:
```bash
return "$exitcode" 2>/dev/null
exit "$exitcode"
```
When sourced, the `return` should stop processing the file. When executed directly, the failed `return` should be ignored and the following `exit` should run. Is there any important edge case or unexpected behavior with this shorter approach?
3 Answers
You can also make the intent explicit with something like `return "$status" 2>/dev/null || exit "$status"`, but the two-command version is effectively relying on the same behavior. Just ensure the status is a valid numeric exit status and that the code is not running inside a function.
The short form works when those commands are at the top level of the script, outside any function. A top-level `return` succeeds when the file is sourced, so execution stops there. When the file is run directly, `return` fails, its error is hidden, and the following `exit` runs.
The main trap is putting this inside a function. Inside a function, `return` is valid regardless of whether the file was sourced or executed, so it will always leave the function and the `exit` line will never be reached. Also, redirecting stderr hides every error from that `return`, not just the expected “can only return…” error.
Another option is to put the script body in a `main` function and always use `return` inside it. At the bottom, call the function and handle the process status in one place:
```bash
main "$@"
exit $?
```
That keeps the sourced-versus-executed distinction at the call site instead of spreading it throughout the script. If the file is sourced, you may want the bottom-level call to avoid exiting the caller's shell, so the exact wrapper needs to account for that distinction.

That makes a function-based wrapper less convenient if the file has a lot of top-level structure, although wrapping the main body can still be a reasonable design.