awk:提取固定数量的行,其中最后一行号可能会有所不同

syn*_*ror 3 awk text-processing

这个问题可能看起来像重复,但只是乍一看。
当然,我将不再需要有关如何编写从数据源中提取固定数量的连续线(例如在本例中为 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}'
Run Code Online (Sandbox Code Playgroud)

这甚至是一个非常方便的单行代码,它将显示系统中占用最多 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}'
Run Code Online (Sandbox Code Playgroud)

(注意:如果第二列中的用户名恰好也是“top”,这可能会产生不需要的结果)

无论如何,我能否得到一个线索如何做到这一点awk(并摆脱grep)?
提前致谢。

Vol*_*gel 6

这不是在回答您的问题,
而是以完全不同的方式解决了您要解决的问题:

完整的命令是这样的(参见下面的示例输出):

ps -o comm,%cpu,%mem --sort -%cpu -A | head -6
Run Code Online (Sandbox Code Playgroud)

我将描述它的部分:

  • 使用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
Run Code Online (Sandbox Code Playgroud)

该进程ps列在完整列表中 - 可以根据父 PID 将其排除。

如果我们想排除top其他地方的进程,我们可以根据命令名称进行操作。

-A选择所有进程将被替换为-N ...

ps ... -N --ppid $$ -C top
Run Code Online (Sandbox Code Playgroud)

由于我们现在需要排除进程,因此我们通常-N选择匹配的进程以外的所有其他进程。

为了排除ps,我们使用它具有当前交互式外壳作为父进程,因此它将具有外壳的父 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
Run Code Online (Sandbox Code Playgroud)


G-M*_*ca' 5

顶部命令| awk 'BEGIN {打印标题;计数=5}
                   NR>=8 { if ($0 ~ / your top regex /) next;
                           打印字段;if (--count == 0) 退出}'

在以 #8 开头的每一行上,如果匹配top,则忽略它。否则,打印您想要的部分。第五次打印一行(不匹配top)时,退出。

  • 非常好的解决方案。作为审美偏好,在 `awk` 中,我可能更倾向于写 `NR&gt;=8 &amp;&amp; !/top/ { print fields; 数数 - ; } !count { 退出; }`。我不确定这是否被专业的 awk 人员认为更惯用,但我个人认为是这样。 (3认同)