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:
- Get the real path of the
source. - Check it is readable, check it is not already loaded by looking-up the global associative array key.
- If so, register it in the global associative array and source it.
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?
- Have it work with older Bash like 3.2
- Have it work with POSIX-shell grammar without array.
readlink -fis available on Busybox. Doreadlinkafter 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 .
POSIX does not like newlines in filenames anyway, so just store files as lines:
Or maybe use case so that you do not
fork:If you want to handle newlines in filenames, convert filename via
xxdorod(both are available on Busybox,odis POSIX) and store hex representation of filenames as lines in the variable.