Reliable automation
Load configuration deliberately
Separate defaults, environment input, and arguments without executing an untrusted configuration file.
10 minute lesson
A script gets its settings from three places: defaults baked into the script, environment variables, and arguments. The tempting fourth is source config.sh — but shell source executes a file as code. Anyone who can edit that file owns every run of your script, with your permissions. For simple configuration, prefer environment variables or parse a constrained format.
Environment variables with explicit policy
Bash parameter expansion states requirements and defaults in one line each. Require a destination with a default interval:
backup_destination=${BACKUP_DESTINATION:?set BACKUP_DESTINATION}
backup_interval=${BACKUP_INTERVAL:-daily}
printf 'destination=%s interval=%s\n' "$backup_destination" "$backup_interval"
${VAR:?message} stops the script with your message when the variable is unset or empty. ${VAR:-default} substitutes a fallback instead. Between the two forms, the script itself documents which settings are required and which have defaults — no separate README to drift out of date.
Verify the three cases
Run with missing, valid, and empty values:
./backup.sh
# ./backup.sh: line 3: BACKUP_DESTINATION: set BACKUP_DESTINATION
BACKUP_DESTINATION=/mnt/backups ./backup.sh
# destination=/mnt/backups interval=daily
BACKUP_DESTINATION= ./backup.sh
# ./backup.sh: line 3: BACKUP_DESTINATION: set BACKUP_DESTINATION
The empty case matters. The colon in :? makes an empty value count as missing — which is what you want, since an empty destination is as useless as none. Without the colon (${VAR?msg}), an empty string would pass the check and fail somewhere deeper.
Validate before use
A value that arrived is not yet a value you can trust:
case $backup_interval in
hourly|daily|weekly) ;;
*) printf 'invalid BACKUP_INTERVAL: %s\n' "$backup_interval" >&2; exit 2 ;;
esac
Validate paths and allowed modes before use. A typo like BACKUP_INTERVAL=dialy should fail loudly at startup, not quietly select some accidental behavior three functions deep.
Two closing rules. Do not print secret configuration — paths and modes are fine to echo, tokens and passwords are not, because logs outlive credential rotations. And if you do adopt a config file one day, treat it as data to parse line by line, never as code to execute.
Lesson completed