从底部提取行直到正则表达式匹配

从底部提取行直到正则表达式匹配

我有这个输出。

[root@linux ~]# cat /tmp/file.txt
virt-top time  11:25:14 Host foo.example.com x86_64 32/32CPU 1200MHz 65501MB
   ID S RDRQ WRRQ RXBY TXBY %CPU %MEM   TIME    NAME
    1 R    0    0    0    0  0.0  0.0  96:02:53 instance-0000036f
    2 R    0    0    0    0  0.0  0.0  95:44:07 instance-00000372
virt-top time  11:25:17 Host foo.example.com x86_64 32/32CPU 1200MHz 65501MB
   ID S RDRQ WRRQ RXBY TXBY %CPU %MEM   TIME    NAME
    1 R    0    0    0    0  0.6 12.0  96:02:53 instance-0000036f
    2 R    0    0    0    0  0.2 12.0  95:44:08 instance-00000372

您可以看到它有两个块,我想提取最后一个块(如果您看到第一个块,它的 CPU 全部为零,我不关心),简而言之,我想提取以下最后几行(注意:有时我有两个以上的实例-*)否则我可以使用“tail -n 2”

1 R    0    0    0    0  0.6 12.0  96:02:53 instance-0000036f
2 R    0    0    0    0  0.2 12.0  95:44:08 instance-00000372

我已经尝试过 sed/awk/grep 和所有可能的方法,但没有接近期望的结果。

答案1

这感觉有点傻,但是:

$ tac file.txt |sed -e '/^virt-top/q' |tac
virt-top time  11:25:17 Host foo.example.com x86_64 32/32CPU 1200MHz 65501MB
   ID S RDRQ WRRQ RXBY TXBY %CPU %MEM   TIME    NAME
    1 R    0    0    0    0  0.6 12.0  96:02:53 instance-0000036f
    2 R    0    0    0    0  0.2 12.0  95:44:08 instance-00000372

GNUtac反转文件(许多非 GNU 系统都有tail -r),sed选择行,直到第一个以virt-top.您可以添加sed 1,2dtail -n +3删除标题。

或者在 awk 中:

$ awk '/^virt-top/ { a = "" } { a = a $0 ORS } END {printf "%s", a}' file.txt 
virt-top time  11:25:17 Host foo.example.com x86_64 32/32CPU 1200MHz 65501MB
   ID S RDRQ WRRQ RXBY TXBY %CPU %MEM   TIME    NAME
    1 R    0    0    0    0  0.6 12.0  96:02:53 instance-0000036f
    2 R    0    0    0    0  0.2 12.0  95:44:08 instance-00000372

它只是将所有行收集到一个变量中,并清除以 开头的行上的该变量virt-top

如果文件非常大,tac+sed解决方案必然会更快,因为它只需要读取文件的尾部,而awk解决方案从顶部读取整个文件。

答案2

ed可以使用正则表达式搜索向上使用?pattern?代替通常的方式/pattern/(从当前位置上方搜索)。例如:

$ printf '%s\n' '?ID?+1,$p' q | ed -s file.txt
    1 R    0    0    0    0  0.6 12.0  96:02:53 instance-0000036f
    2 R    0    0    0    0  0.2 12.0  95:44:08 instance-00000372

答案3

如果您的输入具有固定数量的块,您也可以执行以下操作:

awk '/^virt-top/ && ++n == 2, 0' <your-file

输出从第二次出现virt-top文件末尾的行(0 表示错误的, 意味着结束第一的,最后的范围从未找到)。

答案4

这是另一种处理方法:

$ sed -e '
   /\n/q
   /virt-top/{h;d;}
   H;$!d;g
   s/\n//;D
' file.txt

结果

1 R    0    0    0    0  0.6 12.0  96:02:53 instance-0000036f
2 R    0    0    0    0  0.2 12.0  95:44:08 instance-00000372

相关内容