I'm writing a script to monitor CPU and MEMORY utilization during stability test and in the end I want to present it in a graph or another visual tool. to do so I'm trying to extract %CPU and %MEM from top command by column name

   ##to get indexes of columns I need 
   indexCPU=$(top -b -n 1 | grep PID | tr -s ' ' '\n' | nl -nln |  grep "%CPU" | cut -f1)
   infexMEM=$(top -b -n 1 | grep PID | tr -s ' ' '\n' | nl -nln |  grep "%MEM" | cut -f1)

   ## get values from top in a while loop
   while [ $UPTIME -lt $DURRATION ]; do
   scpu=$(top -b -n 1| grep -w squeezer | tr -s ' ' | cut -d ' ' -f $indexCPU )
   smem=$(top -b -n 1| grep -w squeezer | tr -s ' ' | cut -d ' ' -f $infexMEM )
   echo "$scpu     $smem" >> stabilityTestUsageM.txt
   sleep 300

now when I do this sometimes it gets the right value but in other, I get the values to the left

for example, I got the output


for this:

    top -b -n 1| grep -w squeezer | tr -s ' ' | cut -d ' ' -f $indexCPU

while this is the result for top -b -n 1| grep -w squeezer:

    8048 root      20   0 1953716 442376   8460 S   0.0  2.7   0:30.97 squeezer

Do you have an idea of what's wrong?


1 Answer 1


The problem with your approach is that in the first phase, where you identify the field nr, you omit the "empty field" (that results from leading whitespace in the output of top) in the counting. However, cut with delimiter set to a single space interprets a line starting with a space as having one empty field at the beginning. So, the field numbers determined from your nl -nln is off by one as compared to how cut counts the fields.

As a general rule, however, I would recommend awk instead:

top -b -n 1 | awk '$NF=="squeezer" {print $9}'

should print the 9th field (CPU usage) of the line where the last space-separated field (the command) is "squeezer".

If you want to identify the CPU field by name in order to be sure, the following would work:

top -b -n 1 | awk '!i&&/PID/{for (i=1;i<=NF;i++) {if ($i=="%CPU") break}} '$NF=="squeezer" {print $i}}'

This will first iterate over all fields in the line containing the PID column title and breaks the loop when reaching the one that reads %CPU (so i contains the relevant field number). It then prints that field from the line where the last field is the command you want to profile. As a safeguard, only the first line containing the string PID is considered (in case any process name might contain that string, too).

Notice that this rather simple approach only works if the commands are listed without arguments, i.e. the last space-separated field is indeed only the command, and not any of the command-line arguments.

For the other part, you should ask a separate question as per site guidelines.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .