SC2115: Dangerous rm -rf with Unguarded Variables
Prevent catastrophic deletions from rm -rf with empty variables. Learn safe patterns using ${var:?}, set -u, and directory guards.
Detailed Explanation
The rm -rf Variable Trap
One of the most dangerous patterns in shell scripting is using rm -rf
with a variable that might be empty or unset. An empty variable expands to
nothing, potentially deleting far more than intended.
The Catastrophic Scenario
# If DEPLOY_DIR is unset or empty:
rm -rf $DEPLOY_DIR/*
# Becomes: rm -rf /*
# Deletes everything on the system!
rm -rf "$DEPLOY_DIR"/old
# Becomes: rm -rf ""/old -> rm -rf /old
Safe Patterns
Pattern 1: Use ${var:?}
rm -rf "${DEPLOY_DIR:?DEPLOY_DIR is not set}"/old_release
# Exits with error message if DEPLOY_DIR is unset or empty
Pattern 2: Explicit check
if [ -z "$DEPLOY_DIR" ]; then
echo "ERROR: DEPLOY_DIR is not set" >&2
exit 1
fi
rm -rf "$DEPLOY_DIR"/old_release
Pattern 3: set -u (nounset)
set -u
rm -rf "$DEPLOY_DIR"/old_release
# Exits if DEPLOY_DIR is unset (but not if empty!)
Pattern 4: Absolute path check
# Verify the path looks reasonable
case "$DEPLOY_DIR" in
/home/deploy/*|/opt/app/*|/var/www/*)
rm -rf "$DEPLOY_DIR"/old_release
;;
*)
echo "ERROR: Unexpected DEPLOY_DIR: $DEPLOY_DIR" >&2
exit 1
;;
esac
Additional Safety Measures
- Never use
rm -rf /orrm -rf /*in scripts - Use
--preserve-root(default in GNU rm) - Consider
trash-cliinstead ofrmfor recoverable deletion - Log what will be deleted before actually deleting:
echo "Will delete: $DEPLOY_DIR/old_release" read -r -p "Continue? [y/N] " confirm [[ "$confirm" == "y" ]] && rm -rf "$DEPLOY_DIR"/old_release
Defense in Depth
The safest approach combines multiple guards:
set -euo pipefail
: "${DEPLOY_DIR:?Required}"
[[ "$DEPLOY_DIR" == /opt/app/* ]] || { echo "Bad path" >&2; exit 1; }
rm -rf "$DEPLOY_DIR"/old_release
Use Case
Deployment scripts, cleanup cron jobs, CI/CD pipelines, and any automation that deletes files based on variable paths. This is critical for preventing data loss in production environments.
Try It — Shell Script Linter
Related Topics
Bash Strict Mode: set -euo pipefail Explained
Script Setup
Shell Variable Default Values: Using ${var:-default} and ${var:=default}
Quoting
SC2086: Unquoted Variable Expansion in Shell Scripts
Quoting
SC2164: cd Without Error Handling in Shell Scripts
Error Handling
SC2154: Referenced but Not Assigned Variables in Shell Scripts
ShellCheck Patterns