You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在新版grep中用正则匹配多行并提取最后一组统计数据?

问题描述

我有一个包含多组内存统计数据的文件,每组以含"TOTAL"的行开头和结尾,行数不固定。需要提取最后一组统计数据,原本使用正则(?m)^.*?TOTAL(?s).*?(?m)TOTAL.*?$及命令:

tac con.log | grep -Po "(?m)^.*?TOTAL(?s).*?(?m)TOTAL.*?$" -m1 | tac

在grep 2.5.3环境中能得到正确结果,但在Rocky Linux 9的grep 3.6里完全匹配不到。这个正则在测试工具里有效,推测是新版grep的特性变化导致的,想知道新版grep对这类正则有什么特殊要求,或者有没有其他适合bash脚本的实现方法。

文件内容示例:

2023-01-01 01:00:00 TOTAL MEMORY ALLOCATION CONSUMPTION:
2023-01-01 01:00:00 COMPONENT | USAGE (%)
2023-01-01 01:00:00 class.zzz.aaa.bbb | 32
2023-01-01 01:00:00 class.fff.aaa.ggg | 20
2023-01-01 01:00:00 TOTAL: 52% out of 100% allocated memory consumed
2023-01-01 01:00:00 TOTAL MEMORY ALLOCATION CONSUMPTION:
2023-01-02 01:00:00 COMPONENT | USAGE (%)
2023-01-02 01:00:00 class.xxx.aaa.bbb | 42
2023-01-02 01:00:00 class.bbb.aaa.zzz | 10
2023-01-02 01:00:00 class.zzz.xxx | 21
2023-01-02 01:00:00 class.xxx.sss.ggg | 5
2023-01-02 01:00:00 TOTAL: 78% out of 100% allocated memory consumed
2023-01-01 01:00:00 TOTAL MEMORY ALLOCATION CONSUMPTION:
2023-01-03 01:00:00 COMPONENT | USAGE (%)
2023-01-03 01:00:00 class.xxx.yyy.zzz | 10
2023-01-03 01:00:00 class.xxx.zzz.aaa | 20
2023-01-03 01:00:00 class.zzz.aaa.bbb | 30
2023-01-03 01:00:00 TOTAL: 60% out of 100% allocated memory consumed
新版grep不匹配的原因

grep 3.x版本改用了PCRE2库(旧版是PCRE),对正则的处理逻辑有不少调整,主要影响点:

  1. 内嵌修饰符的作用范围:新版中(?m)和(?s)这类修饰符只对自身位置之后的正则生效,旧版可能是全局生效,原正则里的修饰符切换逻辑在新版中会导致匹配范围混乱。
  2. 多行/单行模式的严格性:PCRE2对^/$在多行模式下的匹配、.在单行模式下的换行匹配规则更严格,原正则的模糊跨行匹配逻辑无法正确捕获内容。
  3. 输入换行处理:新版grep对tac反向后的文本行首行尾匹配逻辑有变化,导致原本的行锚定失效。
解决方案

方法1:修正正则适配新版grep

简化正则,统一修饰符,避免冲突:

tac con.log | grep -Po '(?s)^.*?TOTAL.*?TOTAL.*?$' -m1 | tac

如果要避免中间含TOTAL的行干扰(比如日志里有其他带TOTAL的行),可以更精准匹配开头和结尾的特征:

tac con.log | grep -Po '(?s)^.*?^.*TOTAL MEMORY ALLOCATION CONSUMPTION:.*?^.*TOTAL:.*?$' -m1 | tac

核心是用(?s)开启单行模式让.匹配换行,直接捕获反向文本中第一个完整的TOTAL块,再转回来就是原文件的最后一组。

方法2:用awk实现(更稳定,不受grep版本影响)

awk处理多行块的逻辑更直观,适合这种按固定标记分割的文本:

awk '/TOTAL MEMORY ALLOCATION CONSUMPTION:/ {block=""} {block=block $0 "\n"} /TOTAL:.*allocated memory consumed/ {last_block=block} END {print last_block}' con.log

逻辑说明:

  • 碰到每组的开头行时,清空临时存储块block
  • 每一行都追加到block里
  • 碰到每组的结尾行时,把当前block保存为last_block
  • 最后输出last_block,就是最后一组数据

方法3:用sed实现

利用sed的地址范围匹配:

tac con.log | sed '/TOTAL:.*allocated memory consumed/,/TOTAL MEMORY ALLOCATION CONSUMPTION:/p' | tac | sed '/^$/d'

逻辑说明:

  • tac把文件内容反向
  • sed匹配从第一个结尾行到第一个开头行的内容(对应原文件的最后一组)
  • 再用tac转回来恢复顺序
  • 最后用sed去掉可能的空行

内容的提问来源于stack exchange,提问作者justabitjanky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 22:12:11