Disk Space Monitor
Monitor disk space usage and alert when threshold exceeded
Table of Contents
Automatically monitor disk space usage across all filesystems and alert when usage exceeds threshold.
Overview
This script checks disk space usage on all mounted filesystems, identifies the largest directories consuming space, and sends alerts when usage exceeds a configurable threshold (default 90%). Alerts can be sent via email or logged to syslog.
Use Case: Proactive disk space monitoring to prevent out-of-space errors, automated alerting for capacity planning, and identifying space-consuming directories.
Platform: Linux (all distributions), macOS, Unix-like systems Requirements: Root/sudo privileges for full filesystem access, mail command (optional for email alerts) Execution Time: 30 seconds to 2 minutes depending on filesystem size
The Script
1#!/bin/bash
2
3#############################################################################
4# Disk Space Monitor Script
5#
6# Description: Monitors disk space usage and alerts when threshold exceeded
7# Author: glyph.sh
8# Reference: https://glyph.sh/scripts/disk-space-monitor/
9#
10# Features:
11# - Check all mounted filesystems
12# - Configurable alert threshold (default 90%)
13# - Email alerts or syslog logging
14# - Identify largest directories consuming space
15# - Exclude virtual/temporary filesystems
16#############################################################################
17
18# Configuration
19THRESHOLD=${THRESHOLD:-90} # Alert threshold (percentage)
20EMAIL_TO=${EMAIL_TO:-"admin@example.com"} # Email recipient
21EMAIL_SUBJECT="[ALERT] Disk Space Warning"
22USE_SYSLOG=${USE_SYSLOG:-true} # Log to syslog (true/false)
23USE_EMAIL=${USE_EMAIL:-false} # Send email alerts (true/false)
24TOP_DIRS=${TOP_DIRS:-10} # Number of largest dirs to show
25MIN_DIR_SIZE=${MIN_DIR_SIZE:-100} # Minimum dir size in MB to report
26
27# Filesystems to exclude from monitoring
28EXCLUDE_FS="tmpfs|devtmpfs|squashfs|overlay|none|udev|cgroup"
29
30# Colors for output
31RED='\033[0;31m'
32YELLOW='\033[1;33m'
33GREEN='\033[0;32m'
34BLUE='\033[0;34m'
35NC='\033[0m' # No Color
36
37#############################################################################
38# Functions
39#############################################################################
40
41print_header() {
42 echo -e "${BLUE}========================================${NC}"
43 echo -e "${BLUE} Disk Space Monitor${NC}"
44 echo -e "${BLUE}========================================${NC}"
45 echo ""
46 echo "Threshold: ${THRESHOLD}%"
47 echo "Date: $(date '+%Y-%m-%d %H:%M:%S')"
48 echo ""
49}
50
51log_message() {
52 local level="$1"
53 local message="$2"
54
55 # Log to syslog if enabled
56 if [ "$USE_SYSLOG" = true ]; then
57 logger -t "disk-space-monitor" -p "user.${level}" "$message"
58 fi
59
60 # Print to console
61 case "$level" in
62 "warning")
63 echo -e "${YELLOW}[WARNING]${NC} $message"
64 ;;
65 "error")
66 echo -e "${RED}[ERROR]${NC} $message"
67 ;;
68 "info")
69 echo -e "${GREEN}[INFO]${NC} $message"
70 ;;
71 *)
72 echo "$message"
73 ;;
74 esac
75}
76
77send_email_alert() {
78 local subject="$1"
79 local body="$2"
80
81 if [ "$USE_EMAIL" = true ] && command -v mail >/dev/null 2>&1; then
82 echo "$body" | mail -s "$subject" "$EMAIL_TO"
83 log_message "info" "Email alert sent to $EMAIL_TO"
84 elif [ "$USE_EMAIL" = true ]; then
85 log_message "error" "mail command not found. Cannot send email alerts."
86 fi
87}
88
89check_disk_space() {
90 local alert_triggered=false
91 local alert_message=""
92
93 echo -e "${BLUE}Checking filesystem usage...${NC}"
94 echo ""
95
96 # Header
97 printf "%-20s %8s %8s %8s %5s %s\n" "Filesystem" "Size" "Used" "Avail" "Use%" "Mounted"
98 echo "--------------------------------------------------------------------------------"
99
100 # Get filesystem usage, exclude virtual/temporary filesystems
101 while IFS= read -r line; do
102 # Parse df output
103 filesystem=$(echo "$line" | awk '{print $1}')
104 size=$(echo "$line" | awk '{print $2}')
105 used=$(echo "$line" | awk '{print $3}')
106 avail=$(echo "$line" | awk '{print $4}')
107 percent=$(echo "$line" | awk '{print $5}' | tr -d '%')
108 mountpoint=$(echo "$line" | awk '{print $6}')
109
110 # Skip if percent is not a number
111 if ! [[ "$percent" =~ ^[0-9]+$ ]]; then
112 continue
113 fi
114
115 # Determine status color
116 if [ "$percent" -ge "$THRESHOLD" ]; then
117 color=$RED
118 status="ALERT"
119 alert_triggered=true
120 alert_message="${alert_message}\n${filesystem} mounted on ${mountpoint}: ${percent}% used (${used} / ${size})"
121 elif [ "$percent" -ge $((THRESHOLD - 10)) ]; then
122 color=$YELLOW
123 status="WARN"
124 else
125 color=$GREEN
126 status="OK"
127 fi
128
129 # Print filesystem info
130 printf "${color}%-20s %8s %8s %8s %4s%% %s${NC}\n" \
131 "$filesystem" "$size" "$used" "$avail" "$percent" "$mountpoint"
132
133 # Log if over threshold
134 if [ "$percent" -ge "$THRESHOLD" ]; then
135 log_message "warning" "Filesystem $filesystem on $mountpoint is ${percent}% full"
136 fi
137 done < <(df -h 2>/dev/null | tail -n +2 | grep -vE "$EXCLUDE_FS")
138
139 echo ""
140
141 # Send alert if threshold exceeded
142 if [ "$alert_triggered" = true ]; then
143 local email_body="WARNING: Disk space usage has exceeded ${THRESHOLD}%\n\nAffected filesystems:${alert_message}\n\nHostname: $(hostname)\nDate: $(date)\n\nPlease investigate and free up space."
144 send_email_alert "$EMAIL_SUBJECT" "$(echo -e "$email_body")"
145 fi
146}
147
148find_largest_directories() {
149 echo -e "${BLUE}Finding largest directories...${NC}"
150 echo ""
151
152 # Find directories larger than MIN_DIR_SIZE
153 # This can take time on large filesystems
154 local search_paths=("/var" "/home" "/usr" "/opt" "/tmp")
155
156 for path in "${search_paths[@]}"; do
157 if [ -d "$path" ]; then
158 echo -e "${YELLOW}Analyzing: ${path}${NC}"
159
160 # Use du to find largest directories
161 # -x: stay on one filesystem (don't cross mount points)
162 # -h: human readable
163 # --max-depth=2: limit depth to avoid long scans
164 du -x -h --max-depth=2 "$path" 2>/dev/null | \
165 sort -rh | \
166 head -n "$TOP_DIRS" | \
167 while read -r size dir; do
168 # Convert size to MB for comparison
169 size_mb=$(echo "$size" | sed 's/[^0-9.]//g')
170 unit=$(echo "$size" | sed 's/[0-9.]//g')
171
172 # Convert to MB
173 case "$unit" in
174 G|g) size_mb=$(echo "$size_mb * 1024" | bc 2>/dev/null || echo "$size_mb") ;;
175 K|k) size_mb=$(echo "$size_mb / 1024" | bc 2>/dev/null || echo "$size_mb") ;;
176 esac
177
178 printf " %8s %s\n" "$size" "$dir"
179 done
180 echo ""
181 fi
182 done
183}
184
185show_inode_usage() {
186 echo -e "${BLUE}Checking inode usage...${NC}"
187 echo ""
188
189 printf "%-20s %12s %12s %12s %5s %s\n" "Filesystem" "Inodes" "IUsed" "IFree" "IUse%" "Mounted"
190 echo "--------------------------------------------------------------------------------"
191
192 # Get inode usage
193 while IFS= read -r line; do
194 filesystem=$(echo "$line" | awk '{print $1}')
195 inodes=$(echo "$line" | awk '{print $2}')
196 iused=$(echo "$line" | awk '{print $3}')
197 ifree=$(echo "$line" | awk '{print $4}')
198 ipercent=$(echo "$line" | awk '{print $5}' | tr -d '%')
199 mountpoint=$(echo "$line" | awk '{print $6}')
200
201 # Skip if percent is not a number
202 if ! [[ "$ipercent" =~ ^[0-9]+$ ]]; then
203 continue
204 fi
205
206 # Determine status color
207 if [ "$ipercent" -ge "$THRESHOLD" ]; then
208 color=$RED
209 log_message "warning" "Inode usage on $filesystem ($mountpoint) is ${ipercent}% full"
210 elif [ "$ipercent" -ge $((THRESHOLD - 10)) ]; then
211 color=$YELLOW
212 else
213 color=$GREEN
214 fi
215
216 printf "${color}%-20s %12s %12s %12s %4s%% %s${NC}\n" \
217 "$filesystem" "$inodes" "$iused" "$ifree" "$ipercent" "$mountpoint"
218 done < <(df -i 2>/dev/null | tail -n +2 | grep -vE "$EXCLUDE_FS")
219
220 echo ""
221}
222
223print_summary() {
224 echo -e "${BLUE}========================================${NC}"
225 echo -e "${BLUE} Summary${NC}"
226 echo -e "${BLUE}========================================${NC}"
227 echo ""
228 echo "Monitoring completed at $(date '+%Y-%m-%d %H:%M:%S')"
229 echo "Threshold: ${THRESHOLD}%"
230 echo ""
231
232 # Count filesystems over threshold
233 local count=$(df -h 2>/dev/null | tail -n +2 | grep -vE "$EXCLUDE_FS" | awk '{print $5}' | tr -d '%' | awk -v t="$THRESHOLD" '$1 >= t {count++} END {print count+0}')
234
235 if [ "$count" -gt 0 ]; then
236 echo -e "${RED}WARNING: $count filesystem(s) over ${THRESHOLD}% capacity${NC}"
237 else
238 echo -e "${GREEN}All filesystems are below ${THRESHOLD}% capacity${NC}"
239 fi
240 echo ""
241}
242
243show_help() {
244 cat << EOF
245Usage: $0 [OPTIONS]
246
247Disk Space Monitoring Script
248
249OPTIONS:
250 -t, --threshold NUM Alert threshold percentage (default: 90)
251 -e, --email ADDRESS Email address for alerts
252 -s, --syslog Enable syslog logging (default: true)
253 -m, --mail Enable email alerts (default: false)
254 -d, --top-dirs NUM Number of largest directories to show (default: 10)
255 -i, --inodes Show inode usage
256 -h, --help Display this help message
257
258EXAMPLES:
259 # Basic usage with defaults
260 $0
261
262 # Set custom threshold
263 $0 --threshold 85
264
265 # Enable email alerts
266 $0 --email admin@example.com --mail
267
268 # Show top 20 largest directories
269 $0 --top-dirs 20
270
271ENVIRONMENT VARIABLES:
272 THRESHOLD Alert threshold percentage
273 EMAIL_TO Email recipient address
274 USE_SYSLOG Enable syslog (true/false)
275 USE_EMAIL Enable email alerts (true/false)
276 TOP_DIRS Number of top directories to show
277 MIN_DIR_SIZE Minimum directory size in MB to report
278
279EOF
280 exit 0
281}
282
283#############################################################################
284# Main Script
285#############################################################################
286
287# Parse command line arguments
288SHOW_INODES=false
289
290while [[ $# -gt 0 ]]; do
291 case $1 in
292 -t|--threshold)
293 THRESHOLD="$2"
294 shift 2
295 ;;
296 -e|--email)
297 EMAIL_TO="$2"
298 shift 2
299 ;;
300 -s|--syslog)
301 USE_SYSLOG=true
302 shift
303 ;;
304 -m|--mail)
305 USE_EMAIL=true
306 shift
307 ;;
308 -d|--top-dirs)
309 TOP_DIRS="$2"
310 shift 2
311 ;;
312 -i|--inodes)
313 SHOW_INODES=true
314 shift
315 ;;
316 -h|--help)
317 show_help
318 ;;
319 *)
320 echo "Unknown option: $1"
321 echo "Use -h or --help for usage information"
322 exit 1
323 ;;
324 esac
325done
326
327# Validate threshold
328if ! [[ "$THRESHOLD" =~ ^[0-9]+$ ]] || [ "$THRESHOLD" -lt 1 ] || [ "$THRESHOLD" -gt 100 ]; then
329 echo "Error: Threshold must be between 1 and 100"
330 exit 1
331fi
332
333# Main execution
334print_header
335check_disk_space
336echo ""
337find_largest_directories
338echo ""
339
340if [ "$SHOW_INODES" = true ]; then
341 show_inode_usage
342fi
343
344print_summary
345
346log_message "info" "Disk space monitoring completed"
347
348exit 0Usage
Basic Usage
1chmod +x disk-space-monitor.sh
2./disk-space-monitor.shCustom Threshold
1# Alert when usage exceeds 85%
2./disk-space-monitor.sh --threshold 85Enable Email Alerts
1# Send alerts to specific email
2./disk-space-monitor.sh --email admin@example.com --mailShow More Directories
1# Show top 20 largest directories
2./disk-space-monitor.sh --top-dirs 20Check Inode Usage
1# Include inode usage in report
2./disk-space-monitor.sh --inodesEnvironment Variables
1# Configure via environment variables
2export THRESHOLD=85
3export EMAIL_TO="admin@example.com"
4export USE_EMAIL=true
5export TOP_DIRS=15
6./disk-space-monitor.shWhat It Does
- Checks All Filesystems: Scans all mounted filesystems (excludes virtual/temporary)
- Compares Against Threshold: Identifies filesystems exceeding usage threshold
- Finds Large Directories: Locates largest directories consuming space
- Checks Inode Usage: Optionally monitors inode consumption (can fill up independently)
- Sends Alerts: Logs to syslog and/or sends email notifications
- Color-Coded Output: Visual indicators for usage levels (green/yellow/red)
Automated Monitoring
Cron Job Setup
Add to crontab for automated monitoring:
1# Edit crontab
2crontab -e
3
4# Check disk space every hour
50 * * * * /usr/local/bin/disk-space-monitor.sh --threshold 90 --syslog
6
7# Check every 6 hours with email alerts
80 */6 * * * /usr/local/bin/disk-space-monitor.sh --threshold 90 --email admin@example.com --mail
9
10# Daily detailed report with largest directories
110 8 * * * /usr/local/bin/disk-space-monitor.sh --top-dirs 20 --inodes --email admin@example.com --mailSystemd Timer (Alternative to Cron)
Create systemd service and timer:
1# /etc/systemd/system/disk-space-monitor.service
2[Unit]
3Description=Disk Space Monitor
4After=network.target
5
6[Service]
7Type=oneshot
8ExecStart=/usr/local/bin/disk-space-monitor.sh --threshold 90 --syslog
9User=root
10
11[Install]
12WantedBy=multi-user.target 1# /etc/systemd/system/disk-space-monitor.timer
2[Unit]
3Description=Run Disk Space Monitor hourly
4
5[Timer]
6OnCalendar=hourly
7Persistent=true
8
9[Install]
10WantedBy=timers.targetEnable and start:
1systemctl daemon-reload
2systemctl enable disk-space-monitor.timer
3systemctl start disk-space-monitor.timerCommon Issues This Prevents
- Out of disk space errors
- Application failures due to full filesystems
- Log file growth consuming all space
- Database failures from insufficient space
- System crashes from full root partition
- Backup failures from insufficient capacity
Email Configuration
Install Mail Utilities
1# Debian/Ubuntu
2sudo apt-get install mailutils
3
4# RHEL/CentOS
5sudo yum install mailx
6
7# Configure with local MTA or relay hostTest Email Alerts
1echo "Test message" | mail -s "Test Alert" admin@example.comUnderstanding Output
Filesystem Usage
- Green (<80%): Healthy, plenty of space available
- Yellow (80-89%): Warning, monitor closely
- Red (≥90%): Alert, action required
Largest Directories
Shows directories consuming most space for targeted cleanup:
- Useful for identifying log accumulation
- Finding old backups or cache files
- Locating unexpected large files
Inode Usage
Inodes can be exhausted even with available disk space:
- Happens with many small files
- Check if filesystem shows space but can’t create files
- Use
--inodesflag to monitor
Cleanup Actions
When alerts trigger, investigate these common culprits:
1# Find large files
2find /var -type f -size +100M -exec ls -lh {} \;
3
4# Find old log files
5find /var/log -type f -mtime +30
6
7# Check for core dumps
8find / -name "core.*" -type f 2>/dev/null
9
10# Analyze package cache (Debian/Ubuntu)
11du -sh /var/cache/apt/archives/
12
13# Clean package cache (RHEL/CentOS)
14du -sh /var/cache/yum/Integration with Monitoring Systems
Export to Prometheus
Modify script to export metrics:
1# Add at end of script
2echo "# HELP disk_usage_percent Disk usage percentage" > /var/lib/node_exporter/disk_usage.prom
3df -h | grep -vE "$EXCLUDE_FS" | tail -n +2 | while read line; do
4 mount=$(echo $line | awk '{print $6}')
5 usage=$(echo $line | awk '{print $5}' | tr -d '%')
6 echo "disk_usage_percent{mountpoint=\"$mount\"} $usage" >> /var/lib/node_exporter/disk_usage.prom
7doneWebhook Alerts
Send to Slack/Discord/Teams:
1# Add function for webhook alerts
2send_webhook_alert() {
3 local message="$1"
4 local webhook_url="YOUR_WEBHOOK_URL"
5
6 curl -X POST "$webhook_url" \
7 -H 'Content-Type: application/json' \
8 -d "{\"text\":\"$message\"}"
9}See Also
Download
1curl -O https://glyph.sh/scripts/disk-space-monitor.sh
2chmod +x disk-space-monitor.sh
3./disk-space-monitor.sh --help