Learn Docker With My Newest Course

Dive into Docker takes you from "What is Docker?" to confidently applying Docker to your own projects. It's packed with best practices and examples. Start Learning Docker →

Detect If a Shell Script Is Being Executed or Sourced

blog/cards/detect-if-a-shell-script-is-being-executed-or-sourced.jpg

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.

Quick Jump: An Example Script | Demo Video

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 is true
When you source the above demo script from test-demo:
  • [[ "${BASH_SOURCE[0]}" == "${0}" ]]
    • Evaluates to: [[ ./demo == ./test-demo ]] which is false

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!

Never Miss a Tip, Trick or Tutorial

Like you, I'm super protective of my inbox, so don't worry about getting spammed. You can expect a few emails per month (at most), and you can 1-click unsubscribe at any time. See what else you'll get too.



Comments