How to read from file and convert from string to integer?

Hi all,

I am trying to write a script to be able to

  1. Run top command
  2. Pick the PIDs that are taking more than 90% of CPU time
  3. Get more details like what is the script name and location for that PID
  4. Script should run until I manually kill it by ctrl + C

I have come up with following script for this:

#!/bin/bash
while true; do
filename=`date +"%Y%m%d%H%M%S"`
touch $filename
chmod 755 $filename
top -bn 1 | grep "^ " | awk '{ printf("%-8s %-8s  %-8s  %-8s\n", $1, $9, $10, $12); }' | head -n 10 >> $filename

while read pid cpu mem command
        do
                if [ $cpu -ge 90 ]; then
                        echo "For $pid" >> SlownessStatusReporter_out
                        cat /proc/$pid/cmdline >> SlownessStatusReporter_out
                fi
        done < $filename

sleep 5
done

But I think I am not doing data type conversion properly for $cpu at line

if [ $cpu -ge 90 ]; then

I think when I read from $filename cpu is coming as string and inside if condition, I am trying to use it as integer. This guess is from the fact that I keep getting error for the line if [ $cpu -ge 90 ]; then as below:

./SlownessStatusReporter.sh: line 15: [: %CPU: integer expression expected
./SlownessStatusReporter.sh: line 15: [: 0.0: integer expression expected
./SlownessStatusReporter.sh: line 15: [: 0.0: integer expression expected
./SlownessStatusReporter.sh: line 15: [: 0.0: integer expression expected
./SlownessStatusReporter.sh: line 15: [: 0.0: integer expression expected
./SlownessStatusReporter.sh: line 15: [: 0.0: integer expression expected
./SlownessStatusReporter.sh: line 15: [: 0.0: integer expression expected
./SlownessStatusReporter.sh: line 15: [: 0.0: integer expression expected
./SlownessStatusReporter.sh: line 15: [: 0.0: integer expression expected
./SlownessStatusReporter.sh: line 15: [: 0.0: integer expression expected

When I tried to put $cpu and 90 in double quotes or tried to use >= instead of -ge , I get a different error as below:

./SlownessStatusReporter.sh: line 15: [: %CPU: unary operator expected
./SlownessStatusReporter.sh: line 15: [: 2.0: unary operator expected
./SlownessStatusReporter.sh: line 15: [: 2.0: unary operator expected
./SlownessStatusReporter.sh: line 15: [: 0.0: unary operator expected
./SlownessStatusReporter.sh: line 15: [: 0.0: unary operator expected
./SlownessStatusReporter.sh: line 15: [: 0.0: unary operator expected
./SlownessStatusReporter.sh: line 15: [: 0.0: unary operator expected
./SlownessStatusReporter.sh: line 15: [: 0.0: unary operator expected
./SlownessStatusReporter.sh: line 15: [: 0.0: unary operator expected
./SlownessStatusReporter.sh: line 15: [: 0.0: unary operator expected

Can someone please suggest me how correct this error so my script can work.
I am using:

$ uname -a
Linux hostname 2.6.18-308.13.1.el5 #1 SMP Thu Jul 26 05:45:09 EDT 2012 x86_64 x86_64 x86_64 GNU/Linux
$ echo $SHELL
/bin/bash
$

Thanks in advance.

You might have a few issues to deal with. The use of a file is not really needed as you can use a pipe directing into your while read .... statement:-

top -bn 1 | grep "^ " | while read pid . . . . . . . cpu mem . command .
do
   :
   :

The full-stops in the while read part are just place holders, so you can see I pick out the columns you are after without needed an awk at all.

That will get the values, but if you look at your output (content currently in $filename) presumably has the header record in it, so the first read gets the value %CPU which is not an integer. The other lines do get numeric values, but they are decimal rather than integers and are therefore considered by the test as strings.

We can test and ignore the %CPU record, but the decimal will be a problem. Are you worried about the tenths, or can we truncate them? We can use variable substitution to split the string into the two parts like this:-

whole_bit="${cpu%.*}"
tenth_bit="${cpu#*.}"

You then have the two parts to work with as you please. I'm guessing that as your later test if for over 90% CPU, then the tenths are not a problem and you can just test if $whole_bit is greater than or equal to 90. I'd probably use the -ge notation.

Does this help, or does it just leave you stuck elsewhere?

Robin

As rbatte1 said, you can collect most of what you do into a few lines; here: the awk command:

 top -bn 1 | awk 'NR>7 && $9 > 90 { printf "For %-8s %s\n", $1,  $12 > "Slow_Report"} NR > 17 {exit}'

You may have to adapt this a little, bit I think you get the logics: it assumes the first 7 lines to be the header, then, if field 9 is greater than 90, it prints sth to the slow_report file. After analyzing 10 lines, it quits.

1 Like

Hi rbatte1 and RudiC,
Thanks for your inputs. RudiC I followed your advice and it worked with little tailoring.
My apology for being late to respond here.