3

I'm struggling in if statment

I want the message "The system is highly utilized" pops whenever the memory usage or cpu usage exceeds 70%, now i tried the following 2 conditions in if statment but it gives me error.

# This script monitors CPU and memory usage
RED='\033[0;31m'
NC='\033[0m' # No Color

while : do

Get the current usage of CPU and memory

limit=70.0 cpuUsage=$(top -bn1 | awk '/Cpu/ { print $2}') memTotal=$(free -m | awk '/Mem/{print $2}') memUsage=$(free -m | awk '/Mem/{print $3}') memUsage=$(( (memUsage * 100) / memTotal ))

Print the usage

echo "CPU Usage: $cpuUsage%" echo "Memory Usage: $memUsage%"

Sleep for 1 second

sleep 1

if (( $(echo "$cpuUsage > $limit ; $memUsage > $limit" |bc -l) )) then printf "${RED}The system is highly utilized${NC}\n" else echo The system is not highly utilized fi done

as far as i know the ; runs checks 1st condition and then goes to the 2nd regardless of success. I get this error anyways: 0 : syntax error in expression (error token is "0 ")

3 Answers3

7

bc understands || and &&.

if (( $(echo "$cpuUsage > $limit || $memUsage > $limit" | bc -l) ))
choroba
  • 9,643
  • Thank you so much :) – linuxnoobie Apr 25 '23 at 15:52
  • 1
    I guess bc can be avoided altogether if the floating points are brought to integers that can be calculated/evaluated in bash alone ... e.g. multiplying $limit, $cpuusage, and $memusage by a 100. see for example: https://askubuntu.com/a/1452588 – Raffa Apr 25 '23 at 16:05
2

Although (as you have seen), you can combine expressions using logical || in GNU bc (and in busybox bc), it's not supported by POSIX1.

Since you're already using awk to parse the top and free outputs, an alternative approach would be to do the arithmetic and relational testing in awk as well - then you can use simple integer comparison in the shell (not even requiring bash):

#!/bin/sh

This script monitors CPU and memory usage

RED='\033[0;31m' NC='\033[0m' # No Color

limit=${1:-70.0}

while : do

Get the current usage of CPU and memory

top -bn1 | awk -v limit="$limit" ' /^%Cpu/ {printf "CPU Usage: %.1f%%\n", $2; exit ($2+0 > limit ? 1 : 0)} ' cpuHi=$?

free -m | awk -v limit="$limit" ' /^Mem/ {usage = 100*$3/$2; printf "Memory Usage: %.0f%%\n", usage; exit (usage > limit ? 1 : 0)} ' memHi=$?

sleep 1

if [ "$cpuHi" -ne 0 ] || [ "$memHi" -ne 0 ] then printf "${RED}The system is highly utilized${NC}\n" else printf "The system is not highly utilized\n" fi

done


  1. in fact, POSIX bc doesn't even support relational operators outside of a conditional construct or loop, ex.:

     $ echo '2 > 1 || 1 > 2' | bc
     1
    

    but with warnings enabled:

     $ echo '2 > 1 || 1 > 2' | bc -w
     (standard_in) 1: (Warning) || operator
     (standard_in) 2: (Warning) comparison in expression
     1
    

    and similarly with busybox

     $ echo '2 > 1 || 1 > 2' | busybox bc -w
     bc: POSIX does not allow boolean operators; this is bad: ||
     bc: POSIX does not allow comparison operators outside if or loops
     1
    
steeldriver
  • 136,215
  • 21
  • 243
  • 336
0

To expand a bit on @choroba's answer:

echo "$cpuUsage > $limit ; $memUsage > $limit" |bc -l

will output 2 lines.

A demonstration

$ set -x
+ set -x
$ ans=$(echo "1==1; 2==1" | bc -l)
++ bc -l
++ echo '1==1; 2==1'
+ ans='1
0'
$ if (( $ans )); then echo yes; fi
+ ((  1
0  ))
bash: ((: 1
0 : syntax error in expression (error token is "0 ")
glenn jackman
  • 17,900