I am trying to write a BASH script which will evaluate and show in the terminal a list of all cores and their current load. I am using the output of the /proc/stat
. For example:
cat /proc/stat
user nice system idle iowait irq softirq steal guest guest_nice
cpu 4705 356 584 3699 23 23 0 0 0 0
and evaluating the used CPU time by summing the user
, nice
, system
, irq
, softirq
, steal
and the CPU idle time by summing the idle
, iowait
. Then I am adding the used CPU time + CPU idle time to obtain the total CPU time and dividing the CPU use time to total CPU time.
The problem with this methodology is that this is the average CPU usage since the system was last booted. In order to get the current usage, I need to check two times the /proc/stat
and use the differences between the total CPU time and used CPU time between the two checks and then to divide the result by the difference in time in seconds between them. For this I am using a while
infinite loop complimented with a sleep command. I want to have the output in the following format:
CPU: 10%
CPU0: 15%
CPU1: 5%
CPU2: 7%
CPU3: 13%
And I want the total CPU usage across all cores and the CPU usage per core to update after every sleep automatically. This is my code so far:
#!/bin/bash
PREV_CPU_USE=0
PREV_CPU_IDLE=0
PREV_EPOCH_TIME=0
# Setting the delimiter
IFS=$'\n'
while true; do
# Getting the total CPU usage
CPU_USAGE=$(head -n 1 /proc/stat)
# Getting the Linux Epoch time in seconds
EPOCH_TIME=$(date +%s)
# Splitting the /proc/stat output
IFS=" " read -ra USAGE_ARRAY <<< "$CPU_USAGE"
# Calculating the used CPU time, CPU idle time and CPU total time
CPU_USE=$((USAGE_ARRAY[1] + USAGE_ARRAY[2] + USAGE_ARRAY[3] + USAGE_ARRAY[6] + USAGE_ARRAY[7] + USAGE_ARRAY[8] ))
CPU_IDLE=$((USAGE_ARRAY[4] + USAGE_ARRAY[5]))
# Calculating the differences
DIFF_USE=$((CPU_USE - PREV_CPU_USE))
DIFF_IDLE=$((CPU_IDLE - PREV_CPU_IDLE))
DIFF_TOTAL=$((DIFF_USE + DIFF_IDLE))
DIFF_TIME=$((EPOCH_TIME - PREV_EPOCH_TIME))
#Printing the line and ommiting the trailing new line and using carrier trailer to go to the beginning of the line
echo -en "${USAGE_ARRAY[0]} Usage: $((DIFF_USE*100/(DIFF_TOTAL*DIFF_TIME)))% \\r\\n"
echo -en "${USAGE_ARRAY[0]} Idle: $((DIFF_IDLE*100/(DIFF_TOTAL*DIFF_TIME)))% \\r"
# Assigning the old values to the PREV_* values
PREV_CPU_USE=$CPU_USE
PREV_CPU_IDLE=$CPU_IDLE
PREV_EPOCH_TIME=$EPOCH_TIME
# Sleep for one second
sleep 1
done
Here I have simplified the script and I am actually printing only the current CPU usage and Idle CPU time on two different lines but even though the cpu Idle
is remaining on one line the cpu Usage
is adding new lines like:
cpu Usage: 0%
cpu Usage: 0%
cpu Usage: 0%
cpu Idle: 99%
Is there an option to have the cpu Usage
on one line only for the whole duration of the script?
getline < "/proc/stat"
andsystem("sleep 1")
.