Estou tentando escrever um script BASH que avaliará e mostrará no terminal uma lista de todos os núcleos e sua carga atual. Estou usando a saída do /proc/stat
. Por exemplo:
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
e avaliar o tempo de CPU usado somando o user
, nice
, system
, irq
, softirq
, steal
e o tempo ocioso da CPU somando o idle
, iowait
. Em seguida, estou adicionando o tempo de CPU usado + o tempo ocioso da CPU para obter o tempo total da CPU e dividindo o tempo de uso da CPU pelo tempo total da CPU.
O problema com esta metodologia é que este é o uso médio da CPU desde que o sistema foi inicializado pela última vez. Para obter o uso atual, preciso verificar duas vezes /proc/stat
e usar as diferenças entre o tempo total de CPU e o tempo de CPU usado entre as duas verificações e depois dividir o resultado pela diferença de tempo em segundos entre elas. Para isso estou usando um while
loop infinito complementado com um comando sleep. Eu quero ter a saída no seguinte formato:
CPU: 10%
CPU0: 15%
CPU1: 5%
CPU2: 7%
CPU3: 13%
E quero que o uso total da CPU em todos os núcleos e o uso da CPU por núcleo sejam atualizados automaticamente após cada suspensão. Este é o meu código até agora:
#!/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
Aqui eu simplifiquei o script e, na verdade, estou imprimindo apenas o uso atual da CPU e o tempo de CPU ocioso em duas linhas diferentes, mas mesmo que cpu Idle
permaneça em uma linha, cpu Usage
está adicionando novas linhas como:
cpu Usage: 0%
cpu Usage: 0%
cpu Usage: 0%
cpu Idle: 99%
Existe uma opção para ter cpu Usage
apenas uma linha durante toda a duração do script?
Eu acho que você quer que a
cpu Usage
string seja mostrada na mesma linha todas as vezes e seja seguida pelacpu Idle
linha imediatamente. Para conseguir isso, você pode usartput
eel
(clr_eol
) capacidade do terminal para remover linha ecuu
(parm_up_cursor
) para mover n linhas para cima. Você pode ler sobre os recursos do terminal emman terminfo
. Seu script ficaria assim:Eu adicionei uma variável extra
counter
para fins de depuração. É incrementado após cada impressão para informar ao usuário que a linha antiga é substituída pela nova linha na tela.Também substituí suas chamadas
echo
porprintf
porque é mais portátil.