How to Check Disk Space in Bash

How to Check Disk Space in Bash

There’s nothing quite like the panic of a server going down because a disk quietly filled up overnight. It’s happened to me more than once, and it’s exactly why checking disk space is one of the first things I teach anyone getting comfortable with Bash. It sounds like a simple task, but there’s a surprising amount of depth once you get past the basic df command — from monitoring specific directories, to setting up alerts, to automating cleanup when space gets low.

This guide covers everything from beginner-level commands to advanced scripting patterns for tracking and managing disk usage on Linux and Unix-like systems.

Why Disk Space Monitoring Matters

Running out of disk space isn’t just an inconvenience — it can cause databases to crash, logging to silently stop, and applications to throw obscure errors that have nothing to do with the actual root cause. On production servers, disk space issues are one of the most common causes of downtime, and they’re almost always preventable with basic monitoring.

Checking Overall Disk Usage with df

The df (disk free) command is the starting point for almost every disk space check.

df -h

The -h flag means “human-readable,” converting raw byte counts into KB, MB, or GB. Output looks like this:

Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   32G   16G  67% /
/dev/sda2       100G   85G   10G  90% /data
tmpfs           2.0G  1.2M  2.0G   1% /run

Here’s what each column means:

  • Filesystem — the device or partition being reported on.
  • Size — the total capacity of that filesystem.
  • Used — how much space is currently in use.
  • Avail — how much space remains.
  • Use% — the percentage used, which is usually the number you care about most.
  • Mounted on — the mount point (directory) where that filesystem is attached.

If you only want to check a specific filesystem or mount point, pass its path directly:

df -h /data

Checking Directory and File Sizes with du

While df tells you about entire filesystems, du (disk usage) tells you how much space specific files or directories are consuming. This is what you reach for when df tells you a disk is nearly full, but you need to find out what is actually taking up all that space.

du -sh /var/log

The -s flag summarizes the total instead of listing every subdirectory, and -h again gives human-readable output:

2.3G    /var/log

To break this down by subdirectory and find the biggest offenders, drop the -s flag and sort the output:

du -h --max-depth=1 /var/log | sort -rh

This produces something like:

1.2G    /var/log/nginx
800M    /var/log/mysql
300M    /var/log/journal
  • --max-depth=1 limits the recursion to just one level of subdirectories, so you get a clean overview instead of an overwhelming list.
  • sort -rh sorts human-readable sizes in reverse (largest first), so the biggest space hogs show up at the top.

Finding the Largest Files on Your System

Sometimes the problem isn’t a directory full of many small files, but a handful of massive ones — old log files, forgotten backups, or core dumps. Here’s a one-liner I use constantly:

find / -type f -size +100M -exec ls -lh {} \; 2>/dev/null

Let’s unpack this:

  • find / searches from the root directory downward.
  • -type f restricts results to regular files (not directories or symlinks).
  • -size +100M filters for files larger than 100 megabytes.
  • -exec ls -lh {} \; runs ls -lh on each matching file to show its size in readable form.
  • 2>/dev/null discards permission-denied errors so they don’t clutter your output.

For a live, sortable view, you can pipe this into sort:

find / -type f -size +100M -exec du -h {} \; 2>/dev/null | sort -rh | head -20

This gives you the top 20 largest files on the system, sorted from biggest to smallest.

Checking Inode Usage

Disk space isn’t just about bytes — it’s also about inodes, which are the data structures the filesystem uses to track files. If you have millions of tiny files (a common problem with cache directories or mail queues), you can run out of inodes even if you technically still have free disk space.

df -i

Output:

Filesystem      Inodes  IUsed   IFree IUse% Mounted on
/dev/sda1      3276800 512340 2764460   16% /

If IUse% is near 100% while Use% from the regular df -h output looks fine, you’ve got an inode exhaustion problem, and you’ll need to find and remove large numbers of small files rather than a few big ones.

Automating Disk Space Alerts

Manually checking disk space is fine for a personal laptop, but on a server you actually manage, you want automated alerts before things get critical. Here’s a simple monitoring script I’ve used in production:

#!/bin/bash

THRESHOLD=85
EMAIL="admin@example.com"

df -h | awk 'NR>1 {print $5 " " $6}' | while read -r usage mount; do
  usage_num=$(echo "$usage" | tr -d '%')
  if [ "$usage_num" -ge "$THRESHOLD" ]; then
    echo "Warning: $mount is at ${usage_num}% usage" | mail -s "Disk Space Alert: $mount" "$EMAIL"
  fi
done

Here’s how it works:

  • df -h | awk 'NR>1 {print $5 " " $6}' skips the header row (NR>1) and extracts just the usage percentage and mount point columns.
  • The while read -r usage mount loop processes each line, reading the two values into variables.
  • tr -d '%' strips the percent sign so we can compare the number using standard integer comparison.
  • If usage is greater than or equal to the threshold (85% in this case), it sends an email alert using mail.

You can schedule this to run every 15 minutes with a cron entry:

*/15 * * * * /home/john/scripts/disk_alert.sh

Automating Cleanup When Space Runs Low

Sometimes you want more than just an alert — you want the system to clean up after itself. Here’s a script that clears out log files older than 7 days when disk usage crosses a threshold:

#!/bin/bash

THRESHOLD=90
LOG_DIR="/var/log/myapp"

usage=$(df / | awk 'NR==2 {print $5}' | tr -d '%')

if [ "$usage" -ge "$THRESHOLD" ]; then
  echo "Disk usage at ${usage}%, cleaning old logs..."
  find "$LOG_DIR" -name "*.log" -mtime +7 -exec rm -f {} \;
  echo "Cleanup complete."
else
  echo "Disk usage normal (${usage}%). No action needed."
fi

The key line is find "$LOG_DIR" -name "*.log" -mtime +7 -exec rm -f {} \;, which finds every .log file older than 7 days (-mtime +7) and deletes it. This kind of self-healing script has saved me from late-night pages more than once.

Real-World Use Cases

1. Docker environments. Docker images, containers, and volumes can silently consume huge amounts of disk space. Running docker system df alongside your regular disk checks gives you visibility into container-specific usage, and docker system prune can reclaim space quickly.

2. Database servers. Databases often generate large log or WAL (write-ahead log) files. Monitoring the specific mount point where your database lives, separate from the root filesystem, prevents a bloated log from taking down the whole server.

3. CI/CD build servers. Build artifacts and caches accumulate quickly. A nightly cron job checking du on the build cache directory and clearing anything older than a set number of days keeps things tidy.

4. Backup servers. Since backup servers are, by design, meant to store growing amounts of data, tracking growth trends over time (not just a single snapshot) helps you predict when you’ll need to expand storage.

Best Practices

  • Always check both df -h (overall usage) and df -i (inode usage) — a full disk can be caused by either.
  • Set alert thresholds below 100%, ideally around 80-85%, to give yourself time to react before things become critical.
  • Automate log rotation using tools like logrotate rather than relying solely on manual find and rm cleanup scripts.
  • Keep an eye on /tmp and /var specifically, since these directories tend to accumulate junk over time.
  • Use monitoring tools like ncdu for an interactive, navigable view of disk usage when a script isn’t enough.

Security Considerations

  • Be extremely careful with automated deletion scripts. A misconfigured find ... -exec rm can delete far more than intended if the path or pattern is wrong. Always test with -print instead of -exec rm first to confirm what would be deleted.
  • Restrict who can run disk-cleanup scripts, especially ones with sudo privileges, since a bug in such a script could delete critical system files.
  • Avoid storing sensitive alert credentials (like email or Slack webhook tokens) directly in scripts; use environment variables or a secrets manager instead.

Troubleshooting Common Issues

df shows 100% used, but du doesn’t add up: This usually means a deleted file is still being held open by a running process. Use lsof | grep deleted to find such files, and restart the offending process to release the space.

Disk usage keeps climbing even after deleting files: Check if you’re deleting the actual files or just symlinks. Also verify you’re not deleting from a bind-mounted directory that isn’t the actual storage location.

Permission denied errors while running du or find: Run with sudo if you have the necessary access, or redirect stderr with 2>/dev/null to suppress noise from directories you can’t read.

Common Mistakes to Avoid

  • Forgetting the -h flag and trying to mentally convert raw byte counts.
  • Running du on the entire filesystem without --max-depth, which can take a long time and produce overwhelming output.
  • Writing cleanup scripts without a dry-run mode, risking accidental data loss.
  • Ignoring inode usage and only monitoring byte usage.

FAQs

Q: What’s the difference between df and du? df reports space usage at the filesystem level (how full is this disk/partition), while du reports usage at the file/directory level (how much space does this specific folder use).

Q: Why does df show less free space than I expect? Filesystems usually reserve a percentage of space for root, and journaling filesystems have overhead. Deleted-but-open files (held by running processes) can also account for the gap.

Q: How do I check disk space for a remote server? SSH into it and run the same commands: ssh user@host "df -h".

Q: How can I monitor disk space continuously instead of checking manually? Set up a cron job running a threshold-check script like the one above, or use monitoring tools such as Prometheus with node_exporter for long-term tracking and alerting.

Summary

Disk space monitoring in Bash starts with two commands — df and du — but becomes genuinely powerful once you start scripting alerts, automating cleanup, and tracking inode usage alongside byte usage. Whether you’re managing a single personal server or a fleet of production machines, a few well-placed scripts can catch problems long before they turn into outages.

References

Total
2
Shares

Leave a Reply

Previous Post
How to Run Bash Scripts at Startup

How to Run Bash Scripts at Startup

Next Post
How to Kill Processes in Bash

How to Kill Processes in Bash

Related Posts