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,273
  • 1
  • 30
  • 42
  • 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
  • 131,985
  • 21
  • 239
  • 326
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,625
  • 2
  • 37
  • 60