How to define a shell script to be sourced not run

Assuming that you are running bash, put the following code near the start of the script that you want to be sourced but not executed:

if [ "${BASH_SOURCE[0]}" -ef "$0" ]
then
    echo "Hey, you should source this script, not execute it!"
    exit 1
fi

Under bash, ${BASH_SOURCE[0]} will contain the name of the current file that the shell is reading regardless of whether it is being sourced or executed.

By contrast, $0 is the name of the current file being executed.

-ef tests if these two files are the same file. If they are, we alert the user and exit.

Neither -ef nor BASH_SOURCE are POSIX. While -ef is supported by ksh, yash, zsh and Dash, BASH_SOURCE requires bash. In zsh, however, ${BASH_SOURCE[0]} could be replaced by ${(%):-%N}.


A non-executable file can be sourced but not executed, so, as a first line of defense, not setting the executable flag should be a good hint...

Edit: trick I just stumbled on: make the shebang be any executable that isn't a shell interpreter, /bin/false makes the script return an error (rc!=0)

#!/bin/false "This script should be sourced in a shell, not executed directly"

There are several methods suggested in this Stack Overflow post, of which, I liked the function-based one suggested by Wirawan Purwanto and mr.spuratic best:

The most robust way, as suggested by Wirawan Purwanto, is to check FUNCNAME[1] within a function:

function mycheck() { declare -p FUNCNAME; }
mycheck

Then:

$ bash sourcetest.sh
declare -a FUNCNAME='([0]="mycheck" [1]="main")'
$ . sourcetest.sh
declare -a FUNCNAME='([0]="mycheck" [1]="source")'

This is the equivalent to checking the output of caller, the values main and source distinguish the caller's context. Using FUNCNAME[] saves you capturing and parsing caller output. You need to know or calculate your local call depth to be correct though. Cases like a script being sourced from within another function or script will cause the array (stack) to be deeper. (FUNCNAME is a special bash array variable, it should have contiguous indexes corresponding to the call stack, as long as it is never unset.)

So you can add to the start of the script:

function check()
{
    if [[ ${FUNCNAME[-1]} != "source" ]]   # bash 4.2+, use ${FUNCNAME[@]: -1} for older
    then
        printf "Usage: source %s\n" "$0"
        exit 1
    fi
}
check

Tags:

Shell

Bash