33

I have a script that is littered around my filesystem (side effect of a build process) that sets some global environment variables (LD_LIBRARY_PATH, PATH, ROOTDIR, etc) that need to be in my shell for proper operation. Of course, that means I need to source script.sh or . script.sh to get it to work, and not ./script.sh (which would spawn a new shell and not set the variables in my current shell).

Is there anything I can add to the script to prevent (or warn) someone running ./script.sh ?

7 Answers 7

21

In a shell script, $0 is the name of the currently running script. You can use this to tell if you're being sourced or run like this:

if [[ "$(basename -- "$0")" == "script.sh" ]]; then
    >&2 echo "Don't run $0, source it"
    exit 1
fi
1
  • 1
    (Mac) Didn't work, when I ran script from cmd line ( bash script.sh vs source script.sh)
    – DarkTrick
    Dec 28, 2022 at 5:16
19

Simplest way in bash is:

if [ "$0" = "$BASH_SOURCE" ]; then
    echo "Error: Script must be sourced"
    exit 1
fi

$BASH_SOURCE always contains the name/path of the script.

$0 only contains the name/path of the script when NOT sourced.

So when they match, that means the script was NOT sourced.

2
  • $0 only contains the name/path of the script when NOT sourced. Cannot verify this on Mac.
    – DarkTrick
    Dec 28, 2022 at 5:01
  • However, it worked. (Mac) It seems that BASH_SOURCE is empty when sourced.
    – DarkTrick
    Dec 28, 2022 at 5:15
4

This has been discussed on SO. The most-upvoted answer by @barroyo says to use

[[ "${BASH_SOURCE[0]}" != "${0}" ]] && echo "script ${BASH_SOURCE[0]} is being sourced ..."
1
  • @will: The manual says: An array variable whose members are the source filenames where the corresponding shell function names in the FUNCNAME array variable are defined. How a function?
    – serv-inc
    Apr 18, 2016 at 14:36
1

Another option may be to remove execute permissions. In that case it can not be executed but it can still be sourced.

1
  • 3
    This is incomplete. You can still run scripts with bash script regardless of the execute flag on a script. Also under Cygwin (does this count?) you cannot take away execute flags.
    – Tino
    Feb 15, 2019 at 16:43
1

In addition to check $0 (Mikel answer) may be useful to change extension from .sh to .src, for example. It will help to understand anybody that should not execute this script.

1

Create a custom interpreter source_reminder:

#!/bin/sh
printf "%s\n" "Source me!" >&2
exit 1

Don't forget to make it executable. Then just use it in your script:

#!/path/to/your/source_reminder
foo
bar
whatever

Now if you run the script without sourcing, the reminder will do its job.

1
  • Nice catch. #!/bin/echo do not execute or #!/bin/false or #!/usr/bin/awk BEGIN { print "you must source " ARGV[1]; exit(1) }. However this does not catch the case where the script is executed with something like sh script (as this ignores the Shebang).
    – Tino
    Feb 15, 2019 at 16:57
0

This is going to sound dumb, but if NOTHING should execute it, you can typically just chmod a-x script.sh and any attempts to execute it will fail, though not with a friendly warning message like has been suggested in other answers.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .