4

I need to write a Bash script that does the following:

  1. In the "top" command, I would like to filter the processes by a given COMMAND. In the following I use Google Chrome as an example, which appears as "chrome" in the COMMAND column.
  2. After filtering, there can be zero, one or more processes with COMMAND "chrome" left (this is just to highlight that there is not exactly one process with COMMAND "chrome" in general).
  3. Now I would like to write the current time (hh:mm:ss), the PID of the process and the %CPU value displayed for this process to a file "logfile"
  4. Repeat steps 1 to 3 once every second.

Example: Assuming that there are three "chrome" processes, the output in "logfile" should look something like below (for the first three seconds):

 17:49:12 7954 14.0 17:49:12 7969 9.3 17:49:12 2626 1.3 17:49:13 7954 12.0 17:49:13 7969 6.3 17:49:13 2626 1.2 17:49:14 7954 14.7 17:49:14 7969 8.5 17:49:14 2626 2.1 

My ideas so far: Using the command

 top -b -n 1 -p 7954 | tail -n 2 | head -n 2 | awk '{print $1, $9}' >> logfile 

I filter top by PID (in this case PID == 7954) and the output looks like

 PID %CPU 7954 6.6 

however (since I actually want to filer by COMMAND) I do not know how to filter by COMMAND. In the line above, the "-p 7954" does the filtering for PID==7954, however what do I need to write here to filter by COMMAND==chrome? Also, How can I remove/avoid the header?

According to the time step: I found that the command

 date +"%T" 

gives me the time in the correct format (hh:mm:ss).

So I just struggle with putting these pieces together and fix the filtering problem mentioned above. Thank you for any help!

4 Answers 4

4

Awk can do this; awk '/regex/ { print }' performs the print action only on lines matching regex.

However, you can (and perhaps also should) subsume head and tail as well:

top -b -n 1 | awk 'NR>1 && $10 == "chrome" {print strftime("%T"), $1, $9}' 

... assuming the tenth field of top output contains the command name.

Sign up to request clarification or add additional context in comments.

7 Comments

Thank you that works fine so far! :) The only think still missing is the time stamp. I know that is probably very basic, but I just don't figure out how to add the date +"%" part into this line correctly
Added strftime; can't test right now but that should work. Requires Gawk, apparently, though
Yes perfect, that works perfectly! Thank you once again -you have helped me a lot! :)
-b is an invalid option
@IgorGanapolsky No, it's been there for a long time, but perhaps you have a truly ancient version. I can't find a changelog quickly but I vaguely recall it might have been missing on really old Debian boxes.
|
1

however what do I need to write here to filter by COMMAND==chrome

Write a small script to accomplish this, say calc_proc_mem which looks like below :

#!/bin/bash if [ -z "$1" ] #checking if first param exist then echo "Usage : cal_proc_mem process_name" exit 1 # Exiting with a non-zero value else proc_ids=( $(pgrep "$1") ) if [ ${#proc_ids[@]} -eq 0 ] #checking if if pgrep returned nothing then echo "$1 : Process Not Running/No such process" exit 1 # Exiting with a non-zero value else echo "$1's %CPU-%MEM usage as on $(date +%F)" >> logfile while true do for proc_id in "${proc_ids[@]}" do usage="$(ps -p "$proc_id" -o %cpu,%mem | awk -v pid=$proc_id 'NR==2{printf "PID : %-10d \%CPU : %f \%MEM : %f\n",pid,$1,$2}' 2>/dev/null)" echo -e "$(date +%H:%M:%S)\t$usage" >> logfile done sleep 3 done fi fi 

Run the script as

./calc_proc_mem process_name 

Sample Output

chrome's %CPU-%MEM usage as on 2016-06-27 23:40:33 PID : 3983 %CPU : 1.300000 %MEM : 2.200000 23:40:33 PID : 8448 %CPU : 0.100000 %MEM : 4.300000 23:40:33 PID : 8464 %CPU : 0.000000 %MEM : 0.400000 23:40:33 PID : 8470 %CPU : 0.000000 %MEM : 0.200000 23:40:33 PID : 8526 %CPU : 0.000000 %MEM : 3.000000 23:40:33 PID : 8529 %CPU : 0.000000 %MEM : 0.200000 23:40:33 PID : 8563 %CPU : 0.000000 %MEM : 1.500000 23:40:33 PID : 8655 %CPU : 0.300000 %MEM : 4.900000 23:40:33 PID : 32450 %CPU : 0.300000 %MEM : 2.100000 

Note

Since you've an infinite while-loop running, you need to manually terminate the program using Ctrl C.

Comments

0

You can drop '-p PID' option and next, grep by COMMAND. You can do the next:

top -b -n 1 | grep 'chrome' | tail -n 2 | head -n 2 | awk '{print $1, $9}' 

2 Comments

Hi, thanks your answer, however I think the tail and head is wrong (as it is probably in my post) since it filters out too many chrome processes?
Hi, if you want them all, you just have to drop tail and head commands. Regards.
0

Another command sample to get you going could be:

$ cmd="sleep"; for j in {1..3}; do (${cmd} 123 &); done; $ ts=$(date +"%T"); top -b -n 1| sed s/^[^\ 0123456789].*$//g |grep "${cmd}"|tr -s '\n'| awk '{print $1, $9, $12}'|sed s/^/"${ts} "/g 19:36:51 35122 0.0 sleep 19:36:51 35124 0.0 sleep 19:36:51 35126 0.0 sleep 

It prints the time as given by the date call, and from top: PID, %CPU, and COMMAND field found. The headers and non matching data lines are filtered via sed (no number at start, which could suppress small pids by the way =( thus also a space at line start is accepted) and grep on the command. The time is prepended py sed on start of line injecting the stored timestamp and a blank space to separate.

It is not elegant but might fit your needs to have a start.

The pgrep solutions or using awk with a regex look better ... but at least I enjoyed trying to solve it with top. The tail and head stages in the pipe look suspicious to me ...

1 Comment

Thank you for your answer! It helped me a lot since it was initially the only answer that also addressed the time-stamp issue I had. I was able to solve it with your answer. Therefore I would have accepted your answer, but with tripleee's edit his answer is a little bit more elegant. Nevertheless, a big thank you to you :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.