使用top命令捕获命令过滤的进程的CPU百分比和PID



我需要编写一个Bash脚本,执行以下操作:

  1. 在"top"命令中,我想通过给定的命令过滤进程。下面我以Google Chrome为例,在命令列中显示为"Chrome"。
  2. 过滤后,可以有零,一个或多个进程的命令"chrome"留下(这只是为了强调,没有一个进程的命令"chrome"一般)。
  3. 现在我想写当前时间(hh:mm:ss),进程的PID和这个进程显示的CPU百分比值到一个文件"logfile"
  4. 每秒重复步骤1至3一次。

示例:假设有三个"chrome"进程,"logfile"中的输出应该如下所示(前三秒):

    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

到目前为止我的想法:使用命令

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

我通过PID(在本例中PID == 7954)过滤top,输出看起来像

    PID %CPU
    7954 6.6

然而(因为我实际上想通过命令过滤)我不知道如何通过命令过滤。在上面的行中,"-p 7954"对PID==7954进行过滤,但是我需要在这里写什么来通过COMMAND==chrome进行过滤?此外,我如何删除/避免标题?

根据时间步长:我发现命令

    date +"%T" 

给出了正确格式的时间(hh:mm:ss)。

所以我只是努力把这些碎片放在一起并修复上面提到的过滤问题。谢谢你的帮助!

Awk可以做到这一点;awk '/regex/ { print }'只对匹配regex的行执行print动作。

但是,您也可以(也许也应该)包含headtail:

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

…假设top输出的第10个字段包含命令名

然而,我需要在这里写什么来过滤命令==chrome

编写一个小脚本来完成此操作,例如calc_proc_mem如下所示:

#!/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 : %fn",pid,$1,$2}' 2>/dev/null)"
      echo -e "$(date +%H:%M:%S)t$usage" >> logfile
      done
      sleep 3
    done 
  fi
fi

方式运行脚本
./calc_proc_mem process_name

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

注意

由于您有一个无限的while-loop正在运行,您需要使用Ctrl c手动终止程序。

您可以删除'-p PID'选项,然后,grep by COMMAND。你可以做下一个:

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

另一个示例命令是:

$ 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

它打印由date调用给出的时间,并从top: PID, %CPU和COMMAND字段找到。头和不匹配的数据行通过sed(开始时没有数字,可以通过=(因此行开始处也接受空格)和命令上的grep过滤。时间在行开始处加上py sed,注入存储的时间戳和一个空格来分隔。

它不是优雅的,但可能适合你的需要有一个开始。

pgrep解决方案或使用awk与正则表达式看起来更好…但至少我喜欢用top来解它。

最新更新