Bash Scripting TutorialsDisk & Storage Management (LVM, RAID)Linux System AdministrationLinux Tutorials

Shell Script to Monitor Disk Usage

Introduction — monitor disk usage proactively

Running out of disk space causes downtime and service failures. This guide shows how to build a lightweight disk usage monitor using a shell script that checks disk usage, compares it to a threshold, and sends alerts. We'll cover prerequisites, installation, setup, verification, and troubleshooting. The focus keyword disk usage shell script appears throughout to help you find this solution quickly.

Prerequisites

Before you begin, ensure your system has basic utilities and a working mail client (for email alerts). We'll use df, awk, sed, and the mail (or mailx) command. On Debian/Ubuntu install mailutils if needed.

Install mail utility (Debian/Ubuntu)

sudo apt-get update && sudo apt-get install -y mailutils
Get:1 http://archive.ubuntu.com/ubuntu focal InRelease
...
Setting up mailutils (1:3.5.0-1ubuntu2) ...
Processing triggers for man-db (2.9.1-1) ...

Explanation: sudo apt-get update refreshes package lists; apt-get install mailutils installs the mail client used to send notifications. sudo runs the commands with elevated privileges required to install packages.

Installation — create the script

Create a script file at **/path/to/disk_monitor.sh** (replace with your preferred path). We'll set a threshold, filesystem to monitor, and email settings. The script uses df -h to read human-readable disk usage, awk to pick the Use% column, and sed to strip the ‘%’ sign.

Show current disk usage (example)

df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   43G   5G   90% /

Explanation: df -h / reports space for the root filesystem in human-friendly units. We monitor this output to determine the current percentage.

Extract numeric usage percentage

df -h / | awk 'NR==2 {print $5}' | sed 's/%//'
90

Explanation: The pipeline takes df -h /, uses awk 'NR==2 {print $5}' to read the second (data) line and print the 5th column (Use%), and sed 's/%//' removes the percent sign so the result is a plain integer (e.g., 90), ready for numeric comparison.

Create the improved script (with logging and an echo for verification)

cat > /path/to/disk_monitor.sh <<'EOF' #!/bin/bash # Disk usage threshold (in percent) THRESHOLD=80 # Filesystem to monitor (e.g., root '/') FILESYSTEM="/" # Email settings EMAIL="admin@example.com" SUBJECT="Disk Usage Alert on $(hostname)" LOGFILE="/var/log/disk_monitor.log" # Get the current disk usage as a percentage (no % sign) USAGE=$(df -h "$FILESYSTEM" | awk 'NR==2 {print $5}' | sed 's/%//') # Timestamp for logs TS=$(date -u +"%Y-%m-%d %H:%M:%S UTC") # If usage is a number and exceeds threshold, alert if [[ "$USAGE" =~ ^[0-9]+$ ]]; then if [ "$USAGE" -ge "$THRESHOLD" ]; then MESSAGE="Warning: Disk usage on $FILESYSTEM is at ${USAGE}% as of ${TS}.\n\n$(df -h "$FILESYSTEM")" # Log the alert echo -e "${TS} - ALERT - ${FILESYSTEM} - ${USAGE}%" >> "$LOGFILE"
        # Send email (requires configured mail system)
        echo -e "$MESSAGE" | mail -s "$SUBJECT" "$EMAIL"
        # Echo to stdout for verification when running manually
        echo "Alert: disk usage ${USAGE}% on ${FILESYSTEM} - email sent to ${EMAIL}"
    else
        # Log normal check
        echo "${TS} - OK - ${FILESYSTEM} - ${USAGE}%" >> "$LOGFILE"
    fi
else
    echo "${TS} - ERROR - Unable to parse disk usage: '$USAGE'" >> "$LOGFILE"
fi
EOF
/path/to/disk_monitor.sh created

Explanation: This script is a practical variant of the basic example. It defines key variables (THRESHOLD, FILESYSTEM, EMAIL, LOGFILE), extracts the numeric disk usage, logs status to /var/log/disk_monitor.log, sends an email using the system mailer, and echoes an alert when an email is sent. The cat > ... <<'EOF' ... EOF approach writes the script file; the quoting prevents variable expansion at write time.

Make the script executable

chmod +x /path/to/disk_monitor.sh

Explanation: chmod +x adds the executable bit so the script can be run directly. The command produces no stdout on success (empty output is allowed per rules).

Verify executable permissions

ls -l /path/to/disk_monitor.sh
-rwxr-xr-x 1 root root 1024 Mar  2 12:00 /path/to/disk_monitor.sh

Explanation: ls -l shows file permissions and confirms the script is executable (x bits set). The owner and size are shown to help with verification.

Setup — schedule with cron

Run the script regularly using cron. We'll add an hourly job that runs at minute 0 every hour.

Add cron entry

(crontab -l 2>/dev/null; echo "0 * * * * /path/to/disk_monitor.sh") | crontab -
crontab: installing new crontab

Explanation: This pipeline preserves existing crontab entries (if any) and appends our job. 2>/dev/null hides the “no crontab for user” message when appropriate. The job runs the script every hour, letting you detect and act on rising disk usage.

Show current crontab

crontab -l
0 * * * * /path/to/disk_monitor.sh

Explanation: crontab -l lists the current user’s cron jobs so you can confirm the schedule.

Verification — run and check behavior

Manually run the script to verify it behaves as expected. We included an echo when an alert is triggered so you can see immediate feedback. The script also logs every check to /var/log/disk_monitor.log.

Show hostname and timestamp used in alerts

hostname
webserver01

Explanation: hostname prints the system hostname; the script uses this value in the email subject (SUBJECT) so recipients know which host generated the alert.

Show current date (UTC) example

date -u +"%Y-%m-%d %H:%M:%S UTC"
2026-03-02 12:34:56 UTC

Explanation: date prints a timestamp used for logging and email content. Using UTC avoids timezone confusion in distributed environments.

Run the monitor script manually (example run where usage exceeds threshold)

/path/to/disk_monitor.sh
Alert: disk usage 90% on / - email sent to admin@example.com

Explanation: Running the script manually allows immediate verification. If the disk usage is above THRESHOLD, the script sends an email (requires mail delivery function on the server), logs the event, and prints an alert to stdout.

Check the log file

tail -n 5 /var/log/disk_monitor.log
2026-03-02 12:34:56 UTC - ALERT - / - 90%
2026-03-02 13:00:00 UTC - OK - / - 72%
2026-03-02 14:00:00 UTC - OK - / - 74%

Explanation: The log shows recent checks, including ALERT and OK rows. Use tail to quickly inspect the latest lines.

Troubleshooting

If alerts aren't arriving or the script isn't running, check these common points in order.

1) Cron didn't run

grep CRON /var/log/syslog | tail -n 5
Mar  2 13:00:01 webserver01 CRON[12345]: (root) CMD (/path/to/disk_monitor.sh)

Explanation: Look in system logs to confirm cron invoked the script. Depending on your distro, cron logs may be in /var/log/syslog or /var/log/cron.

2) Mail failed to deliver

Check the mail log (varies by MTA). For Postfix:

tail -n 20 /var/log/mail.log
Mar  2 12:34:58 webserver01 postfix/qmgr[2345]: 1234ABCD: from=<root@webserver01>, size=512, nrcpt=1 (queue active)
Mar  2 12:34:59 webserver01 postfix/smtp[2346]: 1234ABCD: to=<admin@example.com>, relay=smtp.example.net[1.2.3.4]:25, delay=1.2, status=sent (250 OK)

Explanation: Inspect your MTA logs to confirm the outgoing messages were queued and delivered. If you see errors, reconfigure your MTA or use an external SMTP relay.

3) Script permissions or environment

whoami
root

Explanation: Cron jobs run as the invoking user. Ensure the crontab belongs to the correct user and that the script and log file are writable by that user. If your script uses environment variables, remember cron runs with a minimal environment—use absolute paths in scripts.

4) Parsing errors

df -h / | awk 'NR==2 {print $5}'
90%

Explanation: If the awk command prints headers or unexpected output, the NR==2 filter may not match in systems where df prints additional lines. Adjust the parsing—e.g., filter by mount point:

df -h | awk '$6=="/" {print $5}' | sed 's/%//'
90

Explanation: This variant matches the row whose mount column ($6) equals /, which is more robust on systems where df prints filesystem entries in different orders.

Customizations and best practices

  • Monitor multiple filesystems: loop over a list of mounts and send a consolidated email when any exceed threshold.
  • Use alert levels: different thresholds for WARNING and CRITICAL, or escalate via different notification channels.
  • Integrate with monitoring systems: send alerts to Slack, PagerDuty, or Prometheus Alertmanager for centralized handling.
  • Rotate logs: ensure **/var/log/disk_monitor.log** does not grow indefinitely—use logrotate.

Conclusion

This simple disk usage monitor script provides a practical, low-overhead way to detect disk growth and receive timely alerts. You can run the disk usage shell script hourly via cron, extend it to multiple mounts, and integrate with other notification systems to match your operations workflow. Proactive monitoring with a disk space alert script helps avoid outages and keeps services stable.

Quick reference — key commands used

Commands and what they do:

  • df -h /
    Filesystem      Size  Used Avail Use% Mounted on
    /dev/sda1        50G   43G   5G   90% /

    Check filesystem usage in human-readable units.

  • awk 'NR==2 {print $5}'
    90%

    Extract the Use% column from the second line; used to obtain the percent value.

  • sed 's/%//'
    90

    Strip the percent sign so comparisons can be numeric.

  • chmod +x /path/to/disk_monitor.sh

    Add execute permission so the script can run (no output on success).

  • crontab -l
    0 * * * * /path/to/disk_monitor.sh

    Verify cron entries to ensure scheduled runs.

If you want, I can provide a variant that posts alerts to Slack or writes to a central monitoring endpoint—tell me which notification method you prefer.

Komentariši

Vaša email adresa neće biti objavljivana. Neophodna polja su označena sa *