Detect If a Shell Script Is Being Executed or Sourced
We'll go over how to determine this and cover a use case of when you might want to create a script that handles both.
One of the most common use cases is around testing your script, for example:
- Your main script has all of its functions and variables and you execute it normally
- You have a test script where you want to assert your functions and variables work
That immediately sets you up for wanting your script to be called in 2
different ways which is running the script normally (ie. ./demo
) or sourcing
it from another script (ie. . ./demo
).
As for detecting if your script is executed or sourced, this is especially
important if your script can be sourced by a user directly in their shell. You
wouldn’t want to set -e nounset
and other shell options in their current
shell but you would want these options set if the script were run on its own.
# An Example Script
This will make more sense with code.
demo
script:
#!/usr/bin/env bash
export EXAMPLE_DOMAIN="https://example.com"
_curl() {
curl --silent --fail --show-error "${@}"
}
curl_example() {
local -r path="${1:-}"
_curl "${EXAMPLE_DOMAIN}${path}"
}
# Only run this when the script is executed, not sourced:
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
set -o errexit
set -o pipefail
set -o nounset
curl_example "${1:-}"
fi
test-demo
script:
#!/usr/bin/env bash
set -o errexit
set -o pipefail
set -o nounset
# shellcheck disable=SC1091
. ./demo
# TODO: Write assertions to ensure your functions work as expected.
printf "Available functions and environment variables from the demo script:\n\n"
declare -f
env | grep EXAMPLE
The [[ "${BASH_SOURCE[0]}" == "${0}" ]]
condition in the first script is what
lets us detect if a script is executed or sourced.
If you’ve ever worked with Python it’s comparable to __name__ == "__main__"
which lets you run code when your script is called (executed) but not when it’s
imported (sourced).
When you execute the above demo
script:
[[ "${BASH_SOURCE[0]}" == "${0}" ]]
- Evaluates to:
[[ ./demo == ./demo ]]
which istrue
- Evaluates to:
When you source the above demo
script from test-demo
:
[[ "${BASH_SOURCE[0]}" == "${0}" ]]
- Evaluates to:
[[ ./demo == ./test-demo ]]
which isfalse
- Evaluates to:
The rest of both scripts are applying it to an example script, but none of that example code is specific to detecting how your script is called. The video below walks through both scripts in more detail.
# Demo Video
Timestamps
- 0:46 – Jumping straight to the answer
- 1:44 – Running the demo script and ensuring it can be sourced
- 3:05 – This pattern is handy when writing tests for your shell scripts
- 3:32 – Seeing what BASH_SOURCE evaluates to in both cases
- 5:47 – It’s similar to if name equals main in Python
When do you normally use this pattern? Let me know below!