get memory from ps and compare via bash with my limit - bash

I have code that I use in openwrt. I need to check memory which use application
#!/bin/bash
VAR=$(ps | grep sca | grep start | awk '{print $3}')
VAG=$(cat /proc/pid/status | grep -e ^VmSize | awk '{print $2}')
if [ $VAG>28000 ]
then
echo test
fi
No matter if I use VAR or VEG(for example VAR/VAG equal 15000), I can get work this code. I always get "test"

Your if statement is incorrect. The test command (aka [) must receive separate arguments for the operands and the operator. Also, > is for string comparisons; you need to use -gt instead.
if [ "$VAG" -gt 28000 ]
Since you are using bash, you can use the more readable arithmetic command instead of [:
if (( VAG > 28000 ))

Related

Converting string to floating point number without bc in bash shell script

I'm getting load average in a bash shell script like so
load=`echo $(cat /proc/loadavg | awk '{print $1}')`
I know piping to bc
load=`echo $(cat /proc/loadavg | awk '{print $1}') \> 3 | bc -l`
is used in almost all examples of how to cast $load as an int but this box does not have bc installed and I am not allowed to add it.
I tried
int=`perl -E "say $load - 0"`
I tried
int=${load%.*}
I tried
int=`printf -v int %.0f "$load"`
What I want to be able to do is
if [ "$int" -gt 3.5 ]; then
How do I get that to evaluate as intended?
You can use awk to produce a success/failure depending on the condition:
# exit 0 (success) when load average greater than 3.5, so take the branch
if awk '{ exit !($1 > 3.5) }' /proc/loadavg; then
# load average was greater than 3.5
fi
Unfortunately, since "success" is 0 in the shell, you have to invert the logic of the condition to make awk exit with the required status. Obviously, you can do this in a number of ways, such as changing > to <=.
You don't need any external tools (like awk) to read this stuff. Load average from /proc/loadavg is always formatted with two decimal places, so you can do this:
read load _ < /proc/loadavg
if [ ${load/./} -gt 350 ]; then
# do something
fi

get rid of integer expression expected in script

I know this has been asked many times here, but I have looked through all of the previous ones and still can't resolve it. This is just a simple script that checks for a running service and takes the action I define.
#!/bin/bash
SERVICE="$1"
RESULT=`ps -a | sed -n /${SERVICE}/p`
MEM=$(ps aux | sort -rk +4 | grep $1 | grep -v grep | awk '{print $4}' | awk 'NR == 1')
if [ "${RESULT:-null}" = null ]; then
echo "$1 is NOT running"
else
echo "$MEM"
fi
if [ "$MEM" -ge 1 ]; then
mailx -s "Alert: server needs to be checked" me#admins.com
fi
This is the error I get:
./check_service: line 15: [: 5.4: integer expression expected
If I take out the command for the MEM variable and run it outside the script it returns 5.4, which is what I would expect. In my script I have tried changing the "1" to a "1.0" since the output would always be in decimal format, but that did not help. I feel like I am missing something simple here.
Error is due to the fact that bash only supports integer mathematics and your script is comparing 5.4 with 1.
You can fix your script by using:
if [[ ${MEM%.*} -ge 1 ]]l then
mailx -s "Alert: server needs to be checked" me#admins.com
fi
${MEM%.*} will strip part after decimal point and since you're just comparing it with 1 there is no need to have decimal point in variable MEM.

Integer Expression Expected

Code sample :
declare -i a=1
echo "The number of NMON instances running in Performance VM"
ps -ef | grep nmon | awk '{ print $2 }' | wc -l
echo "---------------------------------------------"
num2= ps -ef | grep nmon | awk '{ print $2 }' | wc -l
#num1=${num2%%.*}
#num2 = $(ps -ef | grep nmon | awk '{ print $2 }' | wc -l)
echo "---------------------------------------------"
echo "${num2}"
while [ "$a" -lt "$num2" ]
do
kill -USR2 $(ps -ef | grep nmon | awk '{ print $2 }' | head -1)
a=`expr $a + 1`
done
In the Output i am getting the following error
[: : integer expression expected
in the debug it shows
++ '[' 1 -lt '' ']'
that num2 is empty but when i echo the num2 value i am getting the value correctly.
Output:
The number of NMON instances running in Performance VM
1
1
thanks in advance
The 1 you see in the output is not from echo "${num2}". Like the diagnostics already tell you, this variable is empty.
The general syntax of shell scripts is
[ variable=value ...] command parameters ...
which will assign value to variable for the duration of command, then restore its original value. So the pipeline you are running temporarily sets num2 to the empty string (which apparently it already contained anyway), then runs the pipeline without storing the output anywhere (such as, I imagine you expected, in num2).
Here is a fixed version of your script, with the additional change that the Awk scripts handle stuff you used grep and head and wc for. Because the functionality of these commands is easily replaced within Awk, using external utilities is doubtful (especially so for grep which really is useless when you just run it as a preprocessor for a simple Awk script).
countnmon () {
ps -ef | awk '/[n]mon/ { ++n } END { print n }'
}
declare -i a=1
echo "The number of NMON instances running in Performance VM"
countnmon
echo "---------------------------------------------"
num2=$(countnmon)
#num1=${num2%%.*}
#num2 = $(countnmon)
echo "---------------------------------------------"
echo "${num2}"
while [ "$a" -lt "$num2" ]
do
kill -USR2 $(ps -ef | awk '/[n]mon/ { print $2; exit }')
a=`expr $a + 1`
done
The repeated code could be refactored even further to avoid all code duplication but that will somewhat hamper the readability of this simple script so I have not done that.
Whitespaces matter in bash.
The syntax for command execution is:
command arg1 arg2 ...
So,
var = value # command: var, arg1: =, arg2: value
There's are two exceptions to this rule
exporting variables to an executed command (the variables vanish after the command finishes):
var1=value1 var2=value2 .. command arg1 arg2 ...
assigning a variable (you want this one):
var=value

integer expression expected [bash does not understand .]

I made a small script to kill PID's if they exceed expected cpu usage. It works, but there is a small problem.
Script:
while [ 1 ];
do
cpuUse=$(ps -eo %cpu | sort -nr | head -1)
cpuMax=80
PID=$(ps -eo %cpu,pid | sort -nr | head -1 | cut -c 6-20)
if [ $cpuUse -gt $cpuMax ] ; then
kill -9 "$PID"
echo Killed PID $PID at the usage of $cpuUse out of $cpuMax
fi
exit 0
sleep 1;
done
It works if the integer is three digits long but fails if it drops to two and displays this:
./kill.sh: line 7: [: 51.3: integer expression expected
My question here is, how do I make bash understand the divider so it can kill processes under three digits.
You are probably getting leading space in that variable. Try piping with tr to strip all spaces first:
cpuUse=$(ps -eo %cpu | sort -nr | head -1 | tr -d '[[:space:]]')
Remove text after dot from cpuUse variable:
cpuUse="${cpuUse%%.*}"
Also better to use quotes in if condition:
if [ "$cpuUse" -gt "$cpuMax" ] ; then
OR better use arithmetic operator (( and )):
if (( cpuUse > cpuMax )); then
As you see, bash doesn't grok non-integer numbers. You need to eliminate the decimal point and the following digits from $cpuUse before doing the comparison":
cpuUse=$(sed 's/\..*/' <<<$cpuUse)
However, this is really a job for awk. It will simplify much of what you're doing. Whenever you find yourself with greps of greps, or head and then cuts, you should be dealing with awk. Awk can easily combine these multiple piped seds, greps, cuts, heads, into a single command.
By the way, the correct ps command is:
$ ps -eocpu="",pid=""
Using the ="" will eliminate the heading and simply give you the CPU and PID.
Looking at your program, there's no real need to sort. You're simply looking for all processes above that $cpuMax threshold:
ps -eo %cpu="",pid="" | awk '$1 > 80 {print $2}'
That prints out your PIDs which are over your threshold. Awk automatically loop through your entire input line-by-line. Awk also automatically divides each line into columns, and assigns each a variable from $1 and up. You can change the field divider with the -F parameter.
The above awk says look for all lines where the first column is above 80%, (the CPU usage) and print out the second column (the pid).
If you want some flexibility and be able to pass in different $cpuMax, you can use the -v parameter to set Awk variables:
ps -eo %cpu="",pid="" | awk -vcpuMax=$cpuMax '$1 > cpuMax {print $2}'
Now that you can pipe the output of this command into a while to delete all those processes:
pid=$(ps -eo %cpu="",pid="" | awk -vcpuMax=$cpuMax '$1 > cpuMax {print $2}')
if [[ -n $pid ]]
then
kill -9 $pid
echo "Killed the following processes:" $pid
fi

Shell - Compare Less Than Double

#!/bin/bash
# Obtain the server load
loadavg=`uptime |cut -d , -f 4|cut -d : -f 2`
thisloadavg=`echo $loadavg|awk -F \. '{print $1}'`
if [ "$thisloadavg" -eq "0.01" ]; then
ulimit -n 65536
service nginx restart
service php-fpm restart
fi
The error is:
./loadcheck.sh: line 7: [: 0.01: integer expression expected
I want to do a loadcheck shell script that can compare double instead of integer, as i want assured the load return is less than 0.01 which is 0.00 ,
If I use 0, even if the load is 0.05 , it will still execute the code.
in zsh you can simply use:
if [[ "$thisloadavg" < "0.01" ]]; then
the double [[ construct allows extra tests and in zsh it allows floating point tests.
Bash can't deal with floating point values, so you'll need to use additional commands such as awk, expr or bc to do it for you. For example, using bc:
loadavg=$(uptime | cut -d, -f4 |cut -d: -f2)
low_load=$(echo "$loadavg < 0.01" | bc -l)
if [ $low_load -eq 1 ]; then
# do stuff
fi

Resources