I've been organizing my collection of Bash scripts and created a `base.sh` file to avoid repetition. My goal is to ensure that `base.sh` is sourced uniquely; for example, if `A.sh` sources it and `B.sh` also does, `B.sh` should only source `base.sh` once through `A.sh`. I initially used the guard `[ -n ${__BASE_sh__} ] && return || __BASE_sh__=.` for this.
However, I ran into a problem when `foobar.sh` sources `base.sh`, and then `main.sh` sources `base.sh` and calls `foobar.sh`. `foobar.sh` fails because it doesn't recognize that `base.sh` has been sourced. I thought using `[ -n ${__BASE_sh__} ]` and `[ ! -z ${__BASE_sh__} ]` would yield the same results, but I later discovered that the former can lead to incorrect evaluations when the variable is empty.
I've updated my guard to use proper quoting: `[ -n "${__BASE_sh__}" ] && return || __BASE_sh__=.` Now, everything seems to be working correctly. I also learned that tools like ShellCheck can help identify these types of issues!
5 Answers
If you're looking for alternatives, consider using `declare` to create flags for your functions or scripts. This way, you can monitor which scripts have been loaded without relying solely on the variable state. Just remember: clear naming conventions are key to avoiding conflicts!
I've tackled similar issues by encapsulating all my script logic in a loader script that manages the sourcing of other scripts conditionally. It's all about keeping dependencies clear and ensuring each script gets sourced properly without duplicating efforts. Staying organized with a clear loading sequence can save plenty of headaches down the road!
The issue you faced with sourcing is a common one. Quoting is crucial! When you use `[ -n ${__BASE_sh__} ]`, if the variable is empty, it can lead to unintended behavior. Switching to `[ -n "$__BASE_sh__" ]` resolves that. Plus, using `[[ ... ]]` for tests is generally better in Bash; it handles quotes and word splitting more gracefully.
For a more robust solution, you might want to use an associative array to track sourced scripts. This way, you can check if a script has been sourced before and prevent sourcing it again. Here's a little snippet you can use:
```bash
if ! declare -p SOURCED_SCRIPTS &>/dev/null; then
declare -g -A SOURCED_SCRIPTS
fi
if [[ -z ${SOURCED_SCRIPTS[${BASH_SOURCE[0]}]} ]]; then
SOURCED_SCRIPTS[${BASH_SOURCE[0]}]=1
source your_script.sh
fi
```
This ensures that each script is sourced only once, regardless of how many times it’s called.
Just a tip: Avoid using `.sh` on scripts intended for sourcing since it can cause confusion about their purpose. Instead, you can maintain clarity by using `.lib` or no extension at all for your libraries. It helps in keeping your file management clear, especially when your underlying code might change in the future.
Thanks for the clarification! I didn't realize quoting made such a big difference. I also had issues since I wasn't using ShellCheck before but it pointed out the problems quite quickly!