文本能否执行两次排序?如何不重复解析源数据对awk输出按不同键排序
双维度流量排序内存实现方案
核心思路
仅需解析一次源数据,将awk统计完成的结果在内存中分发到两个独立的排序流程即可,不需要生成临时文件,有两种原生Bash实现方案可选。
方案1:流式并行处理(性能最优)
利用tee配合Bash进程替换特性,流式处理统计结果,不需要将全量统计结果加载到shell变量中,适合统计条目量较大的场景:
zgrep ^1 20211014T00*.gz \ | awk '{print $3,$11,$6,$(NF-7)}' \ | awk 'NR>1{key=$1 " " $2; bytesDown[key]+=$3; bytesUp[key]+=$4} END {for(i in bytesDown) print bytesDown[i], bytesUp[i], i}' \ | tee >(echo -e "=== 下行流量TOP ==="; sort -rnk1 | head) >(echo -e "\n=== 上行流量TOP ==="; sort -rnk2 | head) > /dev/null
说明:
- 全程通过内核匿名管道传输数据,无任何磁盘IO,所有处理都在内存中完成
- 两个排序流程并行执行,性能高于串行处理
- 最后加
> /dev/null是为了丢弃tee的默认标准输出,避免原始统计内容重复打印
方案2:变量缓存(逻辑更直观,输出顺序固定)
如果担心并行处理导致上下行输出顺序混乱,可以先把统计结果缓存到shell变量中,再串行执行两次排序:
# 单次解析源数据,缓存统计结果到变量 stat_result=$(zgrep ^1 20211014T00*.gz \ | awk '{print $3,$11,$6,$(NF-7)}' \ | awk 'NR>1{key=$1 " " $2; bytesDown[key]+=$3; bytesUp[key]+=$4} END {for(i in bytesDown) print bytesDown[i], bytesUp[i], i}') # 按下行排序输出 echo "=== 下行流量TOP ===" echo "$stat_result" | sort -rnk1 | head # 按上行排序输出 echo -e "\n=== 上行流量TOP ===" echo "$stat_result" | sort -rnk2 | head
说明:
- 逻辑简单易懂,输出顺序完全可控
- 4GB内存的环境完全可以承载常规日志的统计结果,即使是百万级的流量条目也不会出现内存不足问题
兼容性提示
两种方案都仅依赖Bash原生特性,无需额外安装工具,如果你执行时遇到语法报错,确认当前使用的是bash而非sh/dash即可,执行echo $SHELL可查看当前使用的shell类型。
内容的提问来源于stack exchange,提问作者imac
相关产品推荐
相关产品推荐

