Issue
Is there something like C++ #pragma once
in bash?
AKA some keyword (or short one-liner), which does this:
if [ "$guard_sourcefile" = true ]; then
return 0
fi
guard_sourcefile=true
...but without the need to change each file's version of the header to have a distinct sourcefile
name.
Solution
As A Header
Since comments on the question make it clear that what you really want is something you can reuse without needing to change it to have a distinct name for each file, a robust approach would be the following three lines:
declare -A already_evaled
[[ ${already_evaled[$BASH_SOURCE]} ]] && return
already_evaled[$BASH_SOURCE]=1
...which of course you can compress to just one line with ;
s:
declare -A already_evaled=(); [[ ${already_evaled[$BASH_SOURCE]} ]] && return; already_evaled[$BASH_SOURCE]=1
Shorter approaches are feasible, but the most obvious ones trade against correctness (assuming that your source file will have a name that is also a valid variable name, or that you'll never source two files with otherwise-identical names from two different directories); it's better put up with the extra verbosity to avoid surprises.
As A Library Itself
Consider putting the following code into runonce.bash
. Because it's being used as a library, it's possible to focus on making it correct and readable, with no need to worry about being terse:
# Source this from any shell library that should only be evaluated a single time
# Intended usage: ''source runonce.bash || return 0''
# Associative arrays require bash 4.0 or later
case $BASH_VERSION in
''|[0-3].*) echo "ERROR: Bash 4.0+ required" >&2; return 2;;
esac
# Detect case where we were directly invoked, or called directly from a script
# (instead of a library that script sourced)
(( ${#BASH_SOURCE[@]} > 2 )) || {
echo "runonce.bash: ERROR: Only source this from other libraries" >&2
return 2
}
# Prefix variables we leave behind to keep them namespaced
declare -A runonce__already_seen
[[ ${runonce__already_seen[${BASH_SOURCE[1]}]} ]] && return 1
# Set prefix variable seen
runonce__already_seen[${BASH_SOURCE[1]}]=1
return 0
...and then, inside any script from which you want to use it:
source runonce.bash || return 0
Answered By - Charles Duffy