这个问题可能看起来像重复的,但只是乍一看。
当然,我不再需要帮助来编写一个提取固定数量的单行代码连续的来自数据源的行(例如本例中的 5 行),例如top
:
$ top -b -n1 | awk 'BEGIN {printf "%23s %7s\n","cpu","mem"} NR==8,NR==12 {printf "%-16s %6s%% %6s%%\n",$12,$9,$10}'
这甚至是一个非常方便的单行代码,它将显示系统中占用最多 CPU 的进程,并在附加列中打印内存使用情况。
到目前为止,一切都很好……然而,事实并非如此那琐碎的。要获取此列表,top
是必要的并且可能(在系统负载较低时)显示本身作为此列表中的进程。我不想这样,因为这些电话是在间隔并且会定期产卵top
(即使只是很短的一段时间)。众所周知,我们想从8号线(NR==8)。但是,如果另一个虚拟桌面中的第二个top
被遗忘在终端中,这也会弄乱列表怎么办?在这种情况下,top
必须省略两个进程,因此要处理的最后一行将为 14。
因此,为了改进此输出并过滤掉其中的每一top
行,计数器似乎是必需的(也许是for
我们用break
? 退出的循环)。不幸的是,我对 for 循环的尝试i = <number>
到目前为止一直没有结果,因为它宁愿按指示多次打印每一行i
。
我提出了一个相当黑客的解决方案,它有效,但可能不适合更复杂的情况:
top -b -n1 | grep -v ' \btop\b$' | awk 'BEGIN {printf "%23s %7s\n","cpu","mem"} NR==8,NR==12 {printf "%-16s %6s%% %6s%%\n",$12,$9,$10}'
(注意:如果第二列中的用户名恰好也是“top”,这可能会产生不需要的结果)
不管怎样,我能得到一个线索如何做到这一点awk
(并摆脱grep
)吗?
提前致谢。
答案1
这并没有回答您的问题,
但它以完全不同的方式解决了您试图解决的问题:
完整的命令是这样的(参见下面的示例输出):
ps -o comm,%cpu,%mem --sort -%cpu -A | head -6
我将描述它的各个部分:
- 用于
ps
对输出进行更多控制 - 仅打印我们需要的三列
-o comm,%cpu,%mem
- 使
ps
数据在内部--sort -%cpu
由CPU排序,反向。 - 列出所有进程
-A
- 显示标题和结果的前 5 行
| head -6
输出类似于第一个命令的输出:
$ ps -o comm,%cpu,%mem --sort -%cpu -A | head -6
COMMAND %CPU %MEM
firefox 8.9 15.5
Xorg 1.3 5.6
parcellite 0.3 1.6
compiz 0.2 1.8
konsole 0.1 0.9
该进程ps
列在完整列表中 - 人们可以根据父 PID 将其排除。
如果我们想排除top
其他地方的进程,我们可以根据命令名称来做到这一点。
选择-A
所有进程将被替换为-N ...
:
ps ... -N --ppid $$ -C top
由于我们现在需要排除进程,因此我们用来-N
选择除我们匹配的进程之外的所有其他进程。
为了排除ps
,我们使用它以当前交互式 shell 作为父进程,因此它将具有该 shell 的父 pid、PPID。当前 shell 的 PID 是$$
。
因此--ppid $$
匹配当前 shell 的所有子进程,我们知道只有一个ps
.
我们还希望排除top
可能在同一台计算机上的其他显示器上运行的进程。我们通过将命令名称与-C top
.
排除ps
进程本身(并且仅此)和所有top
进程的完整命令将是:
ps -o comm,%cpu,%mem --sort -%cpu -N --ppid $$ -C top | head -6
答案2
顶部命令| awk '开始{打印标题;计数=5} NR>=8 { 如果 ($0 ~ /你的顶部正则表达式/) 下一个; 打印领域; if (--count == 0) 退出}'
在以 #8 开头的每一行中,如果匹配top
,则忽略它。否则,打印您想要的部分。第五次打印一行(与 不匹配top
),退出。