Monitor CPU and RAM Usage

monitorsystemawk
4 min read

Quick Answer

The top command in batch mode outputs system metrics non-interactively. Running top -bn1 produces a one-shot snapshot: -b enables batch mode (no terminal control codes), -n1 takes a single sample. The CPU idle percentage on the third line of output reveals load. The free command reports memory in bytes; free -m outputs megabytes. Piping both through awk extracts the specific fields needed for comparison. Without resource monitoring, a runaway process can consume 100% CPU or fill RAM with no warning until the server becomes unresponsive or the OOM killer starts terminating processes. Knowing when CPU stays above 90% for sustained periods distinguishes a traffic spike from a runaway process or a background job that never finished. Works on Ubuntu 22.04 LTS, Debian 12, Fedora 39, and CentOS 9. Schedule with cron every 5 minutes to catch problems before users notice: */5 * * * * /home/user/cpucheck.sh.

The Script

Paste this into monitor.sh. Adjust THRESHOLD and LOG_FILE if you want a different cutoff or log path.

bash
#!/bin/bash CHECK="✓" CROSS="✗" # --- Configuration --- THRESHOLD=80 # Alert when usage exceeds this % LOG_FILE="/var/log/resource-monitor.log" DATE=$(date '+%Y-%m-%d %H:%M:%S') # --- CPU Usage --- CPU=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1 | cut -d',' -f1 | xargs printf "%.0f") # --- RAM Usage --- RAM=$(free | awk '/Mem:/ {printf "%.0f", $3/$2*100}') echo "[$DATE] CPU: ${CPU}% | RAM: ${RAM}%" # --- CPU Alert --- if [ "$CPU" -gt "$THRESHOLD" ]; then echo "$CROSS [$DATE] WARNING: CPU at ${CPU}% (threshold: ${THRESHOLD}%)" | tee -a "$LOG_FILE" else echo "$CHECK CPU OK: ${CPU}%" fi # --- RAM Alert --- if [ "$RAM" -gt "$THRESHOLD" ]; then echo "$CROSS [$DATE] WARNING: RAM at ${RAM}% (threshold: ${THRESHOLD}%)" | tee -a "$LOG_FILE" else echo "$CHECK RAM OK: ${RAM}%" fi

How It Works

Line / pieceWhat it does
THRESHOLD=80The percentage at which a warning fires.
top -bn1Runs top in batch mode for one iteration (non-interactive).
awk '{print $2}'Extracts the CPU usage column from top output.
free | awk '/Mem:/ ...'Parses free output to calculate RAM used / total × 100.
tee -a "$LOG_FILE"Prints to stdout and appends to the log file.
$DATETimestamp so every log entry is traceable.

Step-by-Step Setup

Step 1 — Create the file

bash
nano monitor.sh

Paste the script above, then press Ctrl+X → Y → Enter to save.

Step 2 — Set your threshold

ThresholdBest for
70%Early warning on production — gives time to investigate before impact
80%General-purpose default — recommended for most VPS and cloud instances
90%Last-chance alert — for workloads with legitimate sustained high usage

Edit THRESHOLD=80 at the top of the script to match your environment.

Step 3 — Make it executable and test it

bash
chmod +x monitor.sh ./monitor.sh

You should see output like:

text
[2026-06-03 14:22:01] CPU: 12% | RAM: 54% ✓ CPU OK: 12% ✓ RAM OK: 54%

If CPU or RAM is above the threshold, the warning line fires and appends to LOG_FILE. Check the log after a test run:

bash
cat /var/log/resource-monitor.log

Step 4 — Schedule with cron

The script only helps if it runs automatically. Open your crontab:

bash
crontab -e

Add one of these lines:

bash
# Check every 5 minutes */5 * * * * /home/user/monitor.sh >> /var/log/monitor-cron.log 2>&1 # Check every hour 0 * * * * /home/user/monitor.sh >> /var/log/monitor-cron.log 2>&1 # Check every minute (high-stakes production) * * * * * /home/user/monitor.sh >> /var/log/monitor-cron.log 2>&1

Always redirect cron output to a log

Cron runs silently. Without >> /var/log/monitor-cron.log 2>&1 on your cron line, you will never see warnings from a threshold breach. Redirect both stdout and stderr so every run leaves a trace.

Variations

Send an email when CPU or RAM spikes

Same CPU/RAM probes as above, plus a single email whenever either crosses your threshold — useful instead of silently appending log lines. Requires the mail command (typically mailutils on Debian/Ubuntu); see our bash email alert snippet for install tips, SMTP, and Gmail.

bash
#!/bin/bash # --- Configuration --- THRESHOLD=80 EMAIL="you@example.com" # ← recipient CPU=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1 | cut -d',' -f1 | xargs printf "%.0f") RAM=$(free | awk '/Mem:/ {printf "%.0f", $3/$2*100}') HOST=$(hostname) if [ "$CPU" -gt "$THRESHOLD" ] || [ "$RAM" -gt "$THRESHOLD" ]; then TOP5=$(ps aux --sort=-"%cpu" | head -n 6) { echo "Hostname: $HOST" echo "" echo "CPU usage (approx.): ${CPU}%" echo "RAM usage (approx.): ${RAM}%" echo "" echo "Threshold: ${THRESHOLD}% — at least one metric exceeded." echo "" echo "Top 5 processes by CPU (includes ps header row):" echo "${TOP5}" } | mail -s "⚠ Resource alert on $HOST — CPU ${CPU}% | RAM ${RAM}%" "$EMAIL" fi

Monitor a specific process by name

Pass a substring that appears in ps aux COMMAND column (same idea as grepping logs). Matches every PID whose line contains that substring, sums aggregate %CPU and %MEM, and warns when either crosses a per-watch threshold.

bash
#!/bin/bash # Usage: ./monitor-process.sh nginx 50 # Sums ps %CPU/%MEM for rows whose COMMAND matches $NAME; excludes grep. NAME="$1" PROC_THRESHOLD="${2:-50}" if [ -z "$NAME" ]; then echo "Usage: $0 [threshold-percent]" exit 1 fi MATCHES=$(ps aux | grep "$NAME" | grep -v grep) if [ -z "$MATCHES" ]; then echo "No process matched '$NAME'." exit 0 fi CPU_SUM=$(echo "$MATCHES" | awk '{s += $3} END { printf "%.0f", s+0 }') RAM_SUM=$(echo "$MATCHES" | awk '{s += $4} END { printf "%.0f", s+0 }') echo "[$(date '+%Y-%m-%d %H:%M:%S')] $NAME: CPU agg ${CPU_SUM}% | MEM agg ${RAM_SUM}% (threshold ${PROC_THRESHOLD}%)" if [ "${CPU_SUM:-0}" -gt "$PROC_THRESHOLD" ] || [ "${RAM_SUM:-0}" -gt "$PROC_THRESHOLD" ]; then echo "⚠ WARNING: aggregate CPU or MEM above threshold for '$NAME'" fi

Append JSON log lines for graphing

Every run prints one newline-delimited JSON object and appends it to .jsonl — one record per cron tick — so ingestion tools, log aggregators, or a tiny Python/awk script can build charts.

bash
#!/bin/bash LOG_FILE="/var/log/resource-metrics.jsonl" CPU=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1 | cut -d',' -f1 | xargs printf "%.0f") RAM=$(free | awk '/Mem:/ {printf "%.0f", $3/$2*100}') TS=$(date -u +'%Y-%m-%dT%H:%M:%SZ') LINE=$(printf '{"timestamp":"%s","cpu":%s,"ram":%s}\n' "$TS" "$CPU" "$RAM") echo "$LINE" >> "$LOG_FILE"

Get $200 Free →

Common Mistakes

top output format differs between distros

The awk column for CPU usage is $2 on Ubuntu but may be different on CentOS/RHEL or Alpine. Always test your parsing command on the actual target system before scheduling with cron. Run: top -bn1 | grep "Cpu(s)" and count the columns manually.

The script logs warnings but nobody reads the log

Writing to a log file is pointless if nobody checks it. Combine this with the Send Email Alerts from Bash snippet to get notified when thresholds trip. Or pipe cron output to your inbox.

RAM percentage includes cache/buffers on older systems

On older kernels, free may not show "available" memory correctly. The $3/$2 calculation can overstate usage because Linux aggressively caches disk reads in RAM. On modern Ubuntu (18.04+), this is handled correctly.

Start your Droplet →

View Hosting Plans →

Frequently Asked Questions

How do I check CPU usage in bash?

Use top in batch mode: top -bn1 | grep 'Cpu(s)'. For idle as a number, pipe through awk: top -bn1 | grep 'Cpu(s)' | awk '{print $8}'

How do I check RAM usage in Linux?

Use free: free -h is human-readable. In a script: free | awk '/Mem:/ {printf "%.0f", $3/$2*100}' gives RAM usage as a percentage.

How do I get an alert when CPU is too high?

Capture CPU use in a script, compare to a threshold with an if, then schedule the script with cron every minute or hour (or use email from the variations above).

What is a normal CPU usage percentage on a Linux server?

Under 70% is generally healthy for production. Sustained 80–90%+ usually means something worth inspecting with top or htop.

How do I find which process is using the most CPU?

Run: ps aux --sort=-%cpu | head -10 for the top 10. Or run top interactively and press P to sort by CPU.

BashSnippets logo

Written by Anguishe

Creator of BashSnippets.xyz

bashsnippets.xyz/about

Run this script on a real Linux server

Get $200 free credit — DigitalOcean

Get $200 Free →

Affiliate link · we earn a commission

Need a domain for your next project?

Register with Namecheap — free WHOIS privacy included

Check Domain Prices →

Affiliate link · we earn a commission

Related Snippets

Frequently Asked Questions

How do I run this script?

Save as cpucheck.sh, set CPU_THRESHOLD and RAM_THRESHOLD, run chmod +x cpucheck.sh, then execute ./cpucheck.sh.

Does this work on macOS?

Partially. top works on macOS but output format differs. Use vm_stat instead of free for RAM on macOS.

How do I check CPU usage in bash?

Run top -bn1 and pipe through awk to extract the idle percentage. Subtract from 100 to get CPU usage.

How do I get an alert when CPU is too high?

Compare extracted CPU percentage against a threshold in an if statement, then pipe the alert to mail or a webhook.