Differentiating between running and being sourced in a bash shell script?

Either what I’m asking here is extremely unorthodox/unconventional/risky, or my Google-fu skills just aren’t up to snuff…

In a bash shell script, is there any easy of way of telling if it is getting sourced by another shell script, or is it being run by itself? In other words, is it possible to differentiate between the following two behaviors?

# from another shell script
source myScript.sh

# from command prompt, or another shell script

What I’m thinking of doing is to create an utilities-like shell script containing bash functions that can be made available when sourced. When this script is being run by itself though, I’ll like it to perform certain operations, based on the defined functions too. Is there some kind of an environment variable that this shell script can pick up on, e.g.

some_function() {
    # ...
if [ -z "$IS_SOURCED" ]; then

Preferably, I’m looking for a solution that doesn’t require the caller script to set any flag variables.

edit: I know the difference between sourcing and and running the script, what I’m trying to find out here if it’s possible to tell the difference in the script that is being used (in both ways).

Asked By: h.j.k.


Yes – the $0 variable gives the name of the script as it was run:

$ cat example.sh
script_name=$( basename ${0#-} ) #- needed if sourced no path
this_script=$( basename ${BASH_SOURCE} )
if [[ ${script_name} = ${this_script} ]] ; then
    echo "running me directly"
    echo "sourced from ${script_name}"

$ cat example2.sh
. ./example.sh

Which runs like:

$ ./example.sh
running me directly
$ ./example2.sh
example.sh sourced from example2.sh

That doesn’t cater for being source from an interactive shell, but you get this idea (I hope).

Updated to include BASH_SOURCE – thanks h.j.k

Answered By: user14755

Combining @DarkHeart’s answer with the environment variable BASH_SOURCE seems to do the trick:

$ head example*.sh
==> example2.sh <==
. ./example.sh

==> example.sh <==
if [ "$(basename $0)" = "$(basename $BASH_SOURCE)" ]; then
    echo "running directly"
    echo "sourced from $0"
$ ./example2.sh
sourced from ./example2.sh
$ ./example.sh
running directly

edit Seems to be a simpler solution still if I were to just count the number of elements in BASH_SOURCE‘s array:

if [ ${#BASH_SOURCE[@]} -eq 1 ]; then echo "running directly"; else echo "sourced from $0"; fi
Answered By: h.j.k.

I just created the same kind of library script that works alot like BusyBox. In it, I use the following function to test if it is being sourced…

function isSourced () {
  [[ "${FUNCNAME[1]}" == "source" ]]  && return 0
  return 1

The Bash-maintained FUNCNAME array is essentially a function call stack. $FUNCNAME (or ${FUNCNAME[0]}) is the name of the currently executing function. ${FUNCNAME[1]} is the name of the function that called it, and so on.

The topmost item is a special value for the script itself. It will contain…

  • the word “source” if the script is being sourced
  • the word “main” if the script is being executed AND the test is being done from within a function
  • “”(null) if the script is being executed AND the test is being done outside of any function, that is… at the level of the script itself.

The function above actually only works when called at the script level (which is all I needed). It would fail if called from inside another function because the array item number would be wrong. To make it work anywhere requires finding the top of the stack and testing that value, which is more complicated.

If you need that, you can get the array item number of the “top of the stack” with…

  local _top_of_stack=$(( ${#FUNCNAME[@]} - 1 ))

${#FUNCNAME[@]} is the number of items in the array. As a zero-based array, we subtract 1 to get the last item#.

These three functions are used together to produce a function stack trace similar to Python’s and they may give you a better idea how all this works…

function inspFnStack () {
  local T+="  "
  local _at=
  local _text="n"
  local _top=$(inspFnStackTop)
  local _fn=${FUNCNAME[1]}; [[ $_fn =~ source|main ]]  || _fn+="()"
  local i=_top; ((--i))
  _text+="$i item function call stack for $_fn ...n"
  _text+="| L   BASH_SOURCE{BASH_LINENO called from}.FUNCNAME  n"
  _text+="| ---------------------------------------------------n"
  while (( $i > 0 ))
    _text+="| $i ${T}$(inspFnStackItem $i)n"
    T+="  "
  printf "$_textn"
  return 0

function inspFnStackItem ()  {
  local _i=$1
  local _fn=${FUNCNAME[$_i]}; [[ $_fn =~ source|main ]]  || _fn+="()"
  local _at="${BASH_LINENO[$_i-1]}"; [[ $_at == 1 ]]  && _at="trap"
  local _item="${BASH_SOURCE[$_i]}{${_at}}.$_fn"
  printf "%s" "$_item"
  return 0

function inspFnStackTop () {
  # top stack item is 1 less than length of FUNCNAME array stack
  printf "%dn" $(( ${#FUNCNAME[@]} - 1 ))
  return 0

Note that FUNCNAME, BASH_SOURCE and BASH_LINENO are 3 arrays maintained by bash as if they were one three-dimensional array.

Answered By: DocSalvager

Just want to add that counting the array appears to be unreliable and one should probably not assume source was used since using a dot (.) is very common as well (and predates the source keyword).

For example, for a sourced.sh script containing only echo $0:

$ . sourced.sh 
$ source sourced.sh 
$ chmod +x sourced.sh 
$ ./sourced.sh 
$ cat ./sourced.sh 
echo $0

The comparison solutions suggested work better.

Answered By: ka1l

One way which also works when sourcing from an interactive shell:

if [ $BASH_LINENO -ne 0 ]; then

The BASH_LINENO variable is also an array with all the lines the calling function was executed at. It will be zero if you call the script directly, or an integer corresponding to a line number.

The BASH_* variable docs

Answered By: Borisu
Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.