Simple Bash Script to Monitor CPU, Memory and Disk Usage on Linux in 10 Lines of Code

Monitoring our environment is crucial especially when deploying a new application. Nowadays, companies use open source solutions to monitor system resources on a daily basis. However, when it comes to monitor for a certain amount …

Monitoring our environment is crucial especially when deploying a new application. Nowadays, companies use open source solutions to monitor system resources on a daily basis. However, when it comes to monitor for a certain amount of time for testing purposes, bash scripting comes handy.

In this tutorial, we are going to write a shell or bash script to monitor output a table with three columns showing the percentages of Memory, Disk and CPU used on our machine. The script is going to run for a certain amount of time every 1 second and save the date to a log file in a table form. Later on, the data file can then be imported into a Microsoft Excel sheet for analysis and graphing.

You can use this tool to know what kind of plan you would like to get for your AWS Lightsail instance when migrating your WordPress

Let’s get started!

The script is basically made up of three main parts:

1. Bash Script to Monitor Memory:

free -m | awk 'NR==2{printf "%.2f%%\t\t", $3*100/$2 }'
9.24%

free -m is a command used to show the memory used and free and it gives the below output:

[root@localhost tmp]# free -m
             total       used       free     shared    buffers     cached
Mem:           996         92        904          0         11         31
-/+ buffers/cache:         49        947
Swap:         1583          0       1583

However, what we need from the above output is the total and used memory from the second line. A way to extract data from a given output is by using AWK.

AWK is an programming language used for text processing and data extraction. It is a standard feature of most UNIX systems. awk ‘NR==2’ extracts data form the second line. the $3 and $2 act as holders for the used and total values respectively.

2. Bash Script to Monitor Disk:

df -h | awk '$NF=="/"{printf "%s\t\t", $5}'
7%

The second command outputs the percentage of disk used. df -h outputs data related to disk usage and partitions.

[root@localhost tmp]# df -h
Filesystem                    Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup-lv_root   14G  814M   12G   7% /
tmpfs                         499M     0  499M   0% /dev/shm
/dev/sda1                     485M   32M  428M   7% /boot

awk ‘$NF outputs the number of fields. However,  df -h | awk ‘$NF==”/” will go to that line which contains the character “/”. The $5 will select the field number five from that line. This ensures that the command extracts the correct percentage of disk used (which is %7 in our case).

3. Bash Script to Monitor CPU

top -bn1 | grep load | awk '{printf "%.2f%%\t\t\n", $(NF-2)}'

The top -bn1 command will execute the top command only once (n1 = one iteration) the “b” is used when we want to use “top” in a bash script or to output its data to a file.

“grep load” will output the line which contains the string “load”. $(NF-2) will count the number of fields on that line and decrement 2, thus outputs field #10, or the first 0.00 in the below output.

[root@localhost tmp]# top -bn1 | grep load
top - 19:31:25 up  1:47,  1 user,  load average: 0.00, 0.00, 0.00

After going through the basic parts of the bash scripts, we need to save these commands into variables MEMORY, DISK, and CPU:

MEMORY=$(free -m | awk 'NR==2{printf "%.2f%%\t\t", $3*100/$2 }')
DISK=$(df -h | awk '$NF=="/"{printf "%s\t\t", $5}')
CPU=$(top -bn1 | grep load | awk '{printf "%.2f%%\t\t\n", $(NF-2)}')

We need the script to run for a certain amount of time, let’s say for an hour. In order to do this, we need to use the “while do” loop, with a delay of x seconds after each loop since or depending on your testing:

end=$((SECONDS+3600))
while [ $SECONDS -lt $end ]; do
echo "$MEMORY$DISK$CPU"
sleep 5
done

In order to run a loop for a certain amount of time, we can define a variable $end which takes the  current number of seconds from the time at which the bash script started, hence SECONDS, and adds a number to the current seconds. So an hour would be 3600 seconds.

The second line of the above code snippet states that the while loop will keep executing as long as the current number of seconds is less than the (current number of seconds + 3600). So, we have defined a starting time and an ending time for the loop, in addition to a sleep time that will pause each loop for 5 seconds. Inside the loop is the three variables being assigned every 5 seconds new values, and the echo “$MEMORY$DISK$CPU” which will output the three resource usages.

The complete code is below:

#! /bin/bash
printf "Memory\t\tDisk\t\tCPU\n"
end=$((SECONDS+3600))
while [ $SECONDS -lt $end ]; do
MEMORY=$(free -m | awk 'NR==2{printf "%.2f%%\t\t", $3*100/$2 }')
DISK=$(df -h | awk '$NF=="/"{printf "%s\t\t", $5}')
CPU=$(top -bn1 | grep load | awk '{printf "%.2f%%\t\t\n", $(NF-2)}')
echo "$MEMORY$DISK$CPU"
sleep 5
done

The above code will output the following:

[root@localhost tmp]# ./stats.sh
Memory Disk CPU
9.34% 7% 0.00%
9.34% 7% 0.00%
9.34% 7% 0.00%
9.34% 7% 0.00%
^C[root@localhost tmp]#

You can always output the data to a log file:

[root@localhost tmp]# ./stats.sh >> log.txt

Stress Test

bash script to monitor

Since we barley have any load on the machine, we can use a stress tester to cause the CPU and Memory to load for some time. You can read the man page for the tool here

Issue the below command (on CentOS):

root@localhost tmp]# yum install stress
Failed to set locale, defaulting to C
Loaded plugins: fastestmirror
Determining fastest mirrors
epel/metalink                                                               | 4.2 kB     00:00     
 * base: ba.mirror.garr.it
 * epel: ftp.riken.jp
 * extras: centos.fastbull.org
 * updates: centos.fastbull.org
base                                                                        | 3.7 kB     00:00     
epel                                                                        | 4.3 kB     00:00     
epel/primary_db                                                             | 5.9 MB     00:37     
extras                                                                      | 3.4 kB     00:00     
extras/primary_db                                                           |  37 kB     00:00     
updates                                                                     | 3.4 kB     00:00     
updates/primary_db                                                          | 5.2 MB     00:30     
Setting up Install Process
Resolving Dependencies
--> Running transaction check
---> Package stress.x86_64 0:1.0.4-4.el6 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

===================================================================================================
 Package               Arch                  Version                     Repository           Size
===================================================================================================
Installing:
 stress                x86_64                1.0.4-4.el6                 epel                 36 k

Transaction Summary
===================================================================================================
Install       1 Package(s)

Total download size: 36 k
Installed size: 89 k
Is this ok [y/N]: y
Downloading Packages:
stress-1.0.4-4.el6.x86_64.rpm                                               |  36 kB     00:01     
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
  Installing : stress-1.0.4-4.el6.x86_64                                                       1/1 
  Verifying  : stress-1.0.4-4.el6.x86_64                                                       1/1 

Installed:
  stress.x86_64 0:1.0.4-4.el6                                                                      

Complete!

Now we can use the command “stress” to load our machine. For example, a load average of four is imposed on the system by specifying two CPU-bound processes, one I/O-bound process, and one memory allocator process as follows. The below stress test will run for 1 hour.

[root@localhost tmp]# stress -c 2 -i 1 -m 1 --vm-bytes 128M -t 3600s
stress: info: [1574] dispatching hogs: 2 cpu, 1 io, 1 vm, 0 hdd
stress: info: [1574] successful run completed in 3600s
[root@localhost tmp]# ./stats.sh 
Memory		Disk		CPU
20.48%		7%		1.21%		
20.48%		7%		1.02%		
20.48%		7%		0.94%		
21.89%		7%		1.18%		
20.68%		7%		1.41%		
22.09%		7%		1.62%		
24.10%		7%		1.81%		
24.90%		7%		1.98%		
32.93%		7%		2.14%		
30.32%		7%		2.29%		
20.58%		7%		2.63%		
27.91%		7%		2.82%		
20.48%		7%		2.59%		
20.48%		7%		2.38%		
20.48%		7%		2.19%		
20.48%		7%		2.02%		
20.48%		7%		1.86%		

This concludes our tutorial for how to create a very basic and useful bash script for all the System Administrators out there.

1 thought on “Simple Bash Script to Monitor CPU, Memory and Disk Usage on Linux in 10 Lines of Code”

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.