Inspired by the Php require_once
I figured how it could be implemented for modern Bash with associative arrays here:
a.sh
#!/usr/bin/env bash
declare -gAi __REQUIRES
require_once() {
for p; do
r=$(readlink --canonicalize-existing "$p")
# shellcheck disable=SC1090 # Dynamic source
[[ -r "$r" && 1 -ne "${__REQUIRES[$r]}" ]] && __REQUIRES[$r]=1 && . "$r"
done
}
require_once ./b.sh
require_once ./b.sh
hello
b.sh
hello() {
printf 'I am the hello function in b.sh.\n'
}
This works as intended:
source
.Now I am still wondering how to:
Get the real path of the source in a more portable/standard way not depending on Linux Gnu Tools?
readlink -f
is available on Busybox. Do readlink
after checking that the path exists.
Anyway, https://www.google.com/search?q=readlink+POSIX -> https://medium.com/mkdir-awesome/posix-alternatives-for-readlink-21a4bfe0455c , https://github.com/ko1nksm/readlinkf .
Have it work with older Bash like 3.2
Have it work with POSIX-shell grammar without array.
POSIX does not like newlines in filenames anyway, so just store files as lines:
__REQUIRES=""
if ! printf "%s" "$__REQUIRES" | grep -Fq "$r"; then
__REQUIRES="$__REQUIRES""$r
"
. "$r"
fi
Or maybe use case so that you do not fork
:
__REQUIRES="
"
case "$__REQUIRES" in
*"
$r
"*) ;;
*)
__REQUIRES="$__REQUIRES""$r
"
. "$r"
;;
esac
If you want to handle newlines in filenames, convert filename via xxd
or od
(both are available on Busybox, od
is POSIX) and store hex representation of filenames as lines in the variable.