Checks every real filesystem and prints an alert for any at or above a usage threshold. It prints nothing when all is well, so it suits cron, which emails you only when there is output.
Tested
The script
#!/usr/bin/env bash
# disk-usage-alert.sh: warn when any filesystem is fuller than a threshold.
#
# Usage: disk-usage-alert.sh [-t PERCENT] [MOUNTPOINT...]
# -t PERCENT alert when use is at or above this (default 90)
# MOUNTPOINT only check these; default is every real filesystem
#
# Exit codes: 0 all fine, 1 at least one over the threshold, 2 bad usage.
# Read-only. Suitable for cron: it prints nothing when everything is fine.
set -euo pipefail
usage() { sed -n '4,8p' "$0" | sed 's/^# \{0,1\}//'; }
threshold=90
while getopts ':t:h' opt; do
case "$opt" in
t) threshold="$OPTARG" ;;
h) usage; exit 0 ;;
*) usage >&2; exit 2 ;;
esac
done
shift $((OPTIND - 1))
if ! [[ "$threshold" =~ ^[0-9]+$ ]] || (( threshold > 100 )); then
echo "Error: threshold must be a whole number from 0 to 100, got '$threshold'" >&2
exit 2
fi
# -P keeps each filesystem on one line. Skip RAM-backed, squashfs and CD/DVD
# (iso9660) mounts: optical media always shows 100% full.
# df exits 1 if even one mount cannot be read, so only give up if nothing came back
df_output=$(df -P -x tmpfs -x devtmpfs -x squashfs -x overlay -x iso9660 "$@") || true
if [[ $(printf '%s\n' "$df_output" | wc -l) -lt 2 ]]; then
echo "Error: df returned no filesystems to check" >&2
exit 2
fi
alerts=0
while read -r fs _size _used _avail pct mount; do
use=${pct%\%}
[[ "$use" =~ ^[0-9]+$ ]] || continue
if (( use >= threshold )); then
echo "ALERT: $mount ($fs) is ${use}% full (threshold ${threshold}%)"
alerts=$((alerts + 1))
fi
done < <(printf '%s\n' "$df_output" | tail -n +2)
(( alerts == 0 )) || exit 1
getopts reads -t for the threshold and -h for help. Any other arguments are mount points to check. The help text is the comment block at the top, printed by sed, so the two never drift apart.
Validate
A regular expression checks the threshold is a whole number, and an arithmetic test checks it is 100 or less. Bad input exits with code 2.
Read df
df -P uses the POSIX format, which keeps each filesystem on one line even when the device name is long. The -x options skip RAM-backed filesystems like tmpfs, snap images (squashfs), container layers and CD or DVD mounts, which are always 100% full. df exits with an error if even one mount cannot be read, so the script only gives up if nothing came back at all.
Check each line
tail -n +2 drops the header. read splits each line into fields, and ${pct%\%} strips the percent sign. Any filesystem at or above the threshold gets an ALERT line and the counter goes up.
Exit code
0 means all fine, 1 means at least one alert, 2 means bad usage or no filesystems. Monitoring tools can use the code without parsing the text.
Cookies
No adverts, and nothing that follows you to another site. What we set is what signing in
and the forum need. We count page views with Umami, which sets no cookie and identifies nobody. The one exception is Google reCAPTCHA, which checks our forms are being used by
a person, and that one is yours to decline — nothing is loaded from Google until you
say so.
No adverts, and nothing that follows you to another site. We count page views without a cookie and identify nobody. Google reCAPTCHA checks our forms, and that one is yours to decline.
Cookie Policy ·
Privacy Policy