What you will learn

Monitor disk usage with a two-tier threshold: alert at a warning level, and only run an automated, tightly scoped cleanup past a hard threshold — so a runaway cleanup script never becomes the thing that deletes data it shouldn't.

Before you begin

Automated deletion is inherently risky. This design deliberately narrows what can be auto-deleted (only files matching a specific, safe pattern in a specific directory) rather than a generic "delete oldest files anywhere" approach.

1. Check usage and classify the severity

#!/usr/bin/env bash
set -Eeuo pipefail

MOUNT="/var"
WARN_PCT=80
CRITICAL_PCT=90
CLEANUP_DIR="/var/cache/myapp/tmp"

usage_pct="$(df --output=pcent "$MOUNT" | tail -1 | tr -dc '0-9')"
echo "disk usage on ${MOUNT}: ${usage_pct}%"

if (( usage_pct < WARN_PCT )); then
    echo "ok"
    exit 0
fi

2. Warn without acting between the two thresholds

if (( usage_pct >= WARN_PCT && usage_pct < CRITICAL_PCT )); then
    echo "WARN: ${usage_pct}% >= ${WARN_PCT}%, no automated action taken"
    exit 1
fi

The gap between warning and critical is deliberate: it gives a human time to investigate why usage is climbing before an automated script starts deleting anything. Auto-cleanup only fires past the harder threshold.

3. Scoped, auditable cleanup past the critical threshold

if (( usage_pct >= CRITICAL_PCT )); then
    echo "CRITICAL: ${usage_pct}% >= ${CRITICAL_PCT}%, running scoped cleanup"

    if [[ ! -d "$CLEANUP_DIR" ]]; then
        echo "cleanup dir ${CLEANUP_DIR} missing, aborting cleanup" >&2
        exit 2
    fi

    before_kb="$(du -sk "$CLEANUP_DIR" | cut -f1)"

    # Only ever remove files this app owns, matching a known-safe pattern, older than a day.
    find "$CLEANUP_DIR" -maxdepth 2 -type f -name '*.tmp' -mtime +1 -print -delete

    after_pct="$(df --output=pcent "$MOUNT" | tail -1 | tr -dc '0-9')"
    freed_kb=$(( before_kb - $(du -sk "$CLEANUP_DIR" | cut -f1) ))

    echo "cleanup freed ~${freed_kb}KB, usage now ${after_pct}%"

    if (( after_pct >= CRITICAL_PCT )); then
        echo "STILL CRITICAL after cleanup: ${after_pct}%" >&2
        exit 2
    fi
fi

Hardcoding the deletion pattern (*.tmp, -maxdepth 2, one specific directory) rather than accepting it as a parameter means a misconfigured or compromised caller can't turn this into an arbitrary-file-deletion tool.

Example output

disk usage on /var: 93%
CRITICAL: 93% >= 90%, running scoped cleanup
cleanup freed ~2048000KB, usage now 84%

Verify the result

Fill a scratch mount past both thresholds with dummy .tmp files and confirm: nothing is deleted below WARN_PCT, a warning fires with no deletion between the thresholds, and only matching files under CLEANUP_DIR are removed past CRITICAL_PCT.

Troubleshooting

If usage doesn't drop enough after cleanup, the script correctly re-reports STILL CRITICAL rather than silently succeeding — that's the signal to widen retention policy elsewhere (see auto-log-rotation-pipeline) rather than loosening this script's deletion scope.

Next steps

Alert on both WARN and the post-cleanup STILL CRITICAL case via webhook-alert-dispatcher; treat the latter as higher severity.