A Bash Script for a Quick Linux Server Health Check
Build a lightweight Bash health check that reports CPU, memory, disk, and the busiest processes using standard Linux tools.
When a Linux server feels slow, the first question is rarely “which monitoring platform should I install?” It is usually much simpler: what is consuming the machine right now?
For that first pass, a small shell script can be more useful than a dashboard. My linux-server-stats project combines tools already available on most Linux systems and reports five useful signals:
- Total CPU usage
- Free and used memory percentages
- Free and used space on the root filesystem
- The five processes using the most CPU
- The five processes using the most memory
The result is intentionally small. It is not a replacement for historical monitoring, alerting, or distributed tracing. It is a fast diagnostic snapshot that can be run through an SSH session.
Building the script from standard tools
The script uses top, free, df, and ps. Each tool owns one part of the answer, while awk, sorting, and formatting turn their output into a compact report.
Calculating CPU usage
Running top in batch mode produces a single non-interactive snapshot:
top -bn1
The CPU row includes an idle percentage. The script subtracts that value from 100 to estimate current total usage:
top -bn1 | awk '/Cpu\(s\)/ {
printf "Total CPU Usage: %.2f%%\n", 100 - $8
}'
This is a snapshot, so a short-lived spike can influence the result. For operational monitoring, take repeated samples or use a time-series agent. For an immediate check, however, it answers the right question with almost no setup.
Reading memory usage
free -m reports memory values in mebibytes. The Mem: row contains total, used, and free values, which can be converted into percentages:
free -m | awk '/Mem:/ {
printf "Total Memory Usage (Free / Used): %.2f%% / %.2f%%\n",
$4 * 100 / $2,
$3 * 100 / $2
}'
Linux deliberately uses available memory for filesystem caching, so “free” and “available” are not identical concepts. A production-grade tool should normally highlight the available column as well. This small script stays faithful to its goal: a readable first diagnostic.
Checking the root filesystem
The root filesystem is a useful default because a full root volume can break package installs, logging, and application writes:
df -h /
Filtering the second row removes the header and lets the script present the capacity figures alongside CPU and memory.
Finding expensive processes
Aggregate percentages show that a resource is busy. A process list starts answering why.
ps -eo pid,comm,%cpu --sort=-%cpu | head -n 6
ps -eo pid,comm,%mem --sort=-%mem | head -n 6
The first row is the heading, so head -n 6 gives a label plus five processes. Sorting inside ps avoids needing a separate pipeline for this step.
Running the project
Clone the repository, enter it, make the script executable, and run it:
git clone https://github.com/Mohammed-Aftab-Siddique/linux-server-stats.git
cd linux-server-stats
chmod +x server-stats.sh
./server-stats.sh
Because the implementation reads system information without changing it, it does not need root access under normal Linux configurations.
What this teaches
The value of the exercise is not the number of lines. It demonstrates a useful Unix pattern: let focused tools produce structured text, then compose them into a workflow.
It also draws a clear boundary between diagnostics and monitoring. This script answers what is happening now. A monitoring system adds history, baselines, alert thresholds, dashboards, retention, and correlation across machines. The small diagnostic remains valuable even after those systems exist—especially when an agent is unavailable or you need to verify its story from the host itself.
Sensible next improvements
The script could grow without losing its simplicity:
- Accept warning thresholds through command-line flags
- Report load average and uptime
- Include inode usage, not only disk capacity
- Use
MemAvailablefor a clearer memory signal - Offer JSON output for automation
- Return a non-zero exit code when a threshold is breached
- Add tests using captured command output
The most important design choice is to keep the default output scannable. A server health check is useful when it reduces time-to-understanding, not when it reproduces every number the operating system can expose.
The complete implementation is available in the linux-server-stats repository.