In this lesson, you will learn how to build a robust system for loading external settings into your scripts while safely overriding defaults.
The Strategy of Layered Configuration
When building scripts, hardcoding variables is a recipe for maintenance headaches. A professional approach separates logic from data. By using configuration files, you allow users to customize behavior without touching your code. However, simply "sourcing" a file (using . config.sh) is dangerous because it executes arbitrary code. Instead, we want to parse key-value pairs and apply them safely.
Implementing a Safe Parser
To load settings, we read the file line-by-line, ignore comments, and assign values to variables only if they match our expected format. By using dynamic variable referencing, we can map file keys directly to script variables.
Here is a robust way to load a configuration file:
#!/usr/bin/env bash
# Default settings
PORT=8080
TIMEOUT=30
# Load settings from 'settings.conf'
if [[ -f "settings.conf" ]]; then
while IFS='=' read -r key value; do
# Ignore comments and empty lines
[[ "$key" =~ ^#.*$ || -z "$key" ]] && continue
# Safely assign values to internal variables
case "$key" in
PORT|TIMEOUT)
declare "$key"="$value"
;;
*)
echo "Warning: Ignoring unknown key $key"
;;
esac
done < "settings.conf"
fi
echo "Running on port $PORT with timeout $TIMEOUT"
Why This Logic Matters
- Validation: The
casestatement acts as a whitelist. This prevents a malicious configuration file from injecting unwanted variables into your script’s environment. - Order of Operations: By defining defaults at the top of your script and parsing the file afterward, you allow the configuration file to act as an "override layer." If the key exists in the file, it updates the variable; if it doesn't, the default remains.
- Isolation: Unlike the
sourcecommand, this parsing loop does not execute shell commands found in the config file, keeping your script's execution context isolated and predictable.
Key Takeaway: Always whitelist the keys you intend to parse, and treat external configuration files as data to be sanitized rather than code to be executed.