如何用sed -E匹配日志中含/不含分钟的启动总时间?
提取systemd启动总时间的sed解决方案
需求说明
需要从journalctl筛选出的systemd启动日志中,提取最终的总启动时间。日志中总时间存在两种格式:
- 纯秒数:如
44.753s - 分钟+秒数:如
22min 7.266s
之前尝试的sed命令无法同时匹配两种格式,要么只提取纯秒数,要么只提取含min的时间。
原始日志示例
Sep 15 23:37:31 x systemd[1]: Startup finished in 15.751s (firmware) + 3.034s (loader) + 8.797s (kernel) + 17.169s (userspace) = 44.753s. Sep 17 23:01:24 x systemd[1]: Startup finished in 13.976s (firmware) + 1.998s (loader) + 13.169s (kernel) + 12.014s (userspace) = 41.159s. Sep 20 09:22:15 x systemd[1]: Startup finished in 19.200s (firmware) + 5.931s (loader) + 21min 29.490s (kernel) + 12.643s (userspace) = 22min 7.266s. Sep 23 10:21:06 x systemd[1]: Startup finished in 13.140s (firmware) + 5.571s (loader) + 3min 44.479s (kernel) + 12.065s (userspace) = 4min 15.256s. Sep 23 15:18:53 x systemd[1]: Startup finished in 15.277s (firmware) + 3.152s (loader) + 10.616s (kernel) + 33.766s (userspace) = 1min 2.812s.
之前尝试的sed命令及问题
- 命令1:
sed -E "s/.*systemd\[1\]:.*(([0-9]+min)?[[:space:]]*[0-9]+\.[0-9]{3}s)/\1/"
问题:贪婪匹配导致仅提取纯秒数,含min的行只保留秒数部分 - 命令2:
sed -E "s/.*systemd\[1\]:.*(([0-9]+min)+[[:space:]]*[0-9]+\.[0-9]{3}s)/\1/"
问题:仅匹配含min的行,纯秒数行无输出 - 命令3:
sed -E "s/.*systemd\[1\]:.*((([0-9]+min[[:space:]]+)?[0-9]+\.[0-9]{3}s))/\1/"
问题:同命令1,仅提取纯秒数 - 命令4:
sed -E "s/.*systemd\[1\]:.*([0-9]+min[[:space:]]+[0-9]+\.[0-9]{3}s|[0-9]+\.[0-9]{3}s)/\1/"
问题:同命令1,贪婪匹配吃掉min部分 - 命令5:
sed -E 's/.*systemd\[1\]:.*(([0-9]+min[[:space:]]+[0-9]+\.[0-9]{3}s)|([0-9]+\.[0-9]{3}s)).*/\1\3/'
问题:重复输出纯秒数,含min的行仍只保留秒数
正确的sed命令
方案1:基于位置快速提取
利用总时间在=之后、.之前的特征,直接捕获该区间内容:
sed -E 's/.*= ([^.]+)\./\1/'
效果:对所有日志行都能正确提取:
44.753s 41.159s 22min 7.266s 4min 15.256s 1min 2.812s
方案2:精准匹配时间格式
如果需要严格匹配时间格式(避免意外捕获其他内容),可以用:
sed -E 's/.*= (([0-9]+min )?[0-9]+\.[0-9]{3}s)\./\1/'
原理:
.*=匹配到等号为止,避免贪婪匹配干扰([0-9]+min )?可选匹配分钟部分[0-9]+\.[0-9]{3}s匹配秒数部分(固定三位小数)\./匹配时间末尾的句号,确保只提取总时间
问题根源解释
之前的命令使用.*systemd\[1\]:.*进行前置匹配,.*是贪婪模式,会尽可能多的匹配字符。当行中存在多个时间(如kernel阶段的min格式时间),贪婪匹配会优先覆盖前面的min部分,导致正则只捕获最后出现的纯秒数,而非等号后的总时间。
内容的提问来源于stack exchange,提问作者mor3dr3ad
相关产品推荐
相关产品推荐

