如何按前N个字符排序含附属无时间戳行的日志文件或数组
处理带续行的日志并按时间戳排序
针对你遇到的日志排序问题——需要将无时间戳的续行归属到上一行带时间戳的条目,再整体按时间戳排序——这里有一个简洁可靠的awk解决方案,完美适配你的需求。
问题分析
你的日志是多文件grep的结果,存在两种行:
- 起始行:以
YYYYMMDD-HH:MM:SS.sss:格式的时间戳开头 - 续行:无时间戳,属于上一行的起始行
我们需要把每个「起始行+后续所有连续续行」作为一个独立条目,按起始行的时间戳排序后,再还原原来的行结构。
解决方案:Awk脚本
Awk天生擅长处理这种需要上下文关联的文本操作,我们可以用它把每个条目打包成一个字符串,按时间戳排序后再输出。
完整脚本
创建一个名为sort_logs.awk的文件,内容如下:
BEGIN { # 匹配时间戳行的正则表达式 timestamp_regex = "^[0-9]{8}-[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}:" } # 匹配到时间戳起始行时,保存上一个条目并开始新条目 $0 ~ timestamp_regex { if (current_timestamp != "") { # 用「时间戳_序号」作为键,避免相同时间戳的条目被覆盖 key = current_timestamp "_" count++ records[key] = current_record } # 提取当前时间戳(前23个字符),初始化当前条目 current_timestamp = substr($0, 1, 23) current_record = $0 next } # 非时间戳行,追加到当前条目末尾 { if (current_timestamp != "") { current_record = current_record "\n" $0 } } # 处理完所有行后,排序并输出所有条目 END { # 保存最后一个条目 if (current_timestamp != "") { key = current_timestamp "_" count++ records[key] = current_record } # 对条目按键排序(时间戳优先,原顺序次之) n = asorti(records, sorted_keys) for (i=1; i<=n; i++) { print records[sorted_keys[i]] } }
使用方法
在终端中运行以下命令,替换your_log_file.txt为你的日志文件名:
awk -f sort_logs.awk your_log_file.txt
脚本工作原理
- 识别起始行:用正则表达式匹配以标准时间戳开头的行,作为每个条目的起点。
- 打包条目:遇到新的起始行时,先把上一个打包好的条目存入数组;非起始行则直接追加到当前条目末尾。
- 排序输出:所有行处理完成后,对数组的键(
时间戳_序号)进行排序——时间戳保证整体顺序,序号保证相同时间戳的条目保留原出现顺序——最后逐个输出条目。
替代方案(Sed+Sort)
如果你偏好更简洁的命令行组合,也可以用Sed先合并续行,排序后再拆分,但注意如果日志中存在@@@这类标记字符会出错:
# 合并续行→排序→拆分续行 sed '/^[0-9]{8}-/!{H;$!d};x;s/\n/@@@/g' your_log_file.txt | sort | sed 's/@@@/\n/g'
这个方案虽然简短,但可靠性不如Awk脚本,建议优先选择Awk方案。
内容的提问来源于stack exchange,提问作者qwedcxzas
相关产品推荐
相关产品推荐

