paul paul - 6 months ago 15
Bash Question

Importing function definitions from a bash script w/o running it

I have two scripts foo.sh and bla.sh

foo.sh

#bin/bash
test(){
"hello world"
}
test
exit 1


bla.sh

#bin/bash
source ./a.sh
echo a.test


The problem is that source seems like run the a.sh script, and of course then after exit 1 b never is executed.

ThereĀ“s any way to just use the function test from bla without run the whole script?

Answer

If you want your script to be capable of being sourced without running its contents, you should design it that way.

#!/bin/bash

# put your function definitions here
mytest() { echo "hello world"; }

# ...and choose one of the following, depending on your requirements:

# more reliable approach, *except* doesn't detect being sourced from an interactive or
# piped-in shell.
(( ${#BASH_SOURCE[@]} > 1 )) && return

# less reliable approach in general, but *does* detect being sourced from an interactive
# shell.
[[ "$BASH_SOURCE" != "$0" ]] && return

# put your actions to take when executed here
mytest
exit 1

Why it works: (( ${#BASH_SOURCE[@]} > 1 ))

If the array of source files (per stack frame) is of length more than one in the root of a script, the only way to have any additional stack frame is for the script to have been sourced from elsewhere.

The caveat, here, is that an interactive shell (or a noninteractive shell with its input coming from a pipeline or other non-file source) doesn't have an entry in the BASH_SOURCE array, so if we're sourced from a human-driven shell -- or a shell reading its input from a pipeline or other non-file source -- there will still be only one entry.

Why it works: [[ $BASH_SOURCE != "$0" ]]

BASH_SOURCE is an array of source files, one element per stack frame; like all bash arrays, when expanded without explicitly indexing into a specific element, it defaults to the first one (that being the file currently being executed or sourced). $0 is the name of the command being executed, which is not updated by the source command.

Thus, if these don't match, we know that we were sourced.

Important caveat: Note that there are circumstances where depending on $0 will necessarily be broken: cat input-script | bash can't accurately know the location on disk where input-script came from, so it will always detect this as being sourced. See the Why $0 is NOT an option section of BashFAQ #28 to understand these limitations in detail.

Comments