Shell脚本用awk筛选同firm下时间差小于30秒的3条及以上CSV记录
awk实现CSV分组连续时间差筛选方案
需求规则
处理orders.csv文件,提取符合以下要求的记录:
- 按第三列
firm字段分组,仅保留分组总记录数≥3的firm相关记录 - 同一firm下的记录按文件原始顺序排列,相邻记录第二列
time字段时间差小于30秒的记录保留,时间差≥30秒的记录排除 - 若同一firm下存在多段满足「相邻差<30秒且段内记录数≥3」的连续序列,输出第一段或全部符合段的记录均可。
样例输入
orders.csv格式:
date,time,firm,user,id 20220520,12:00:00,TEST1,ABC,FNT0060 20220520,12:00:05,TEST2,ABC,FNT0061 20220520,12:00:10,TEST1,ABC,FNT0062 20220520,12:00:25,TEST1,ABC,FNT0063 20220520,12:00:45,TEST1,ABC,FNT0064 ...
预期输出
date,time,firm,user,id 20220520,12:00:00,TEST1,ABC,FNT0060 20220520,12:00:10,TEST1,ABC,FNT0062 20220520,12:00:25,TEST1,ABC,FNT0063
已实现的零散逻辑
- 全局时间差计算(未按firm分组,存在逻辑缺陷):
awk -F '[:,]' '{t=$2*3600+$3*60+$4} NR>1{printf( "%.6f\n", t-p)}{p=t}' $orders.csv > abc.csv
注:原命令中x为笔误,awk乘法运算符为*
2. 筛选记录数≥3的firm全量记录(未做时间差过滤):
awk -F',' 'NR==FNR{cnt[$3]++; next} cnt[$3]>=3' $orders.csv $orders.csv > firm.csv
完整实现命令
无需生成中间文件,单次执行awk双遍历即可完成所有逻辑,直接输出结果:
awk -F',' ' # 第一遍遍历:统计每个firm的总记录数,过滤记录数不足3的分组 NR==FNR { if (NR>1) firm_cnt[$3]++ next } # 输出CSV表头 FNR==1 { print $0 next } # 跳过总记录数不足3的firm记录 firm_cnt[$3] < 3 { next } { # 拆分time字段为秒级时间戳,方便计算差值 split($2, time_arr, ":") cur_sec = time_arr[1]*3600 + time_arr[2]*60 + time_arr[3] # 首次处理该firm,初始化连续段缓存 if (!($3 in last_sec)) { seg_len[$3] = 0 delete seg_cache[$3] } else { time_diff = cur_sec - last_sec[$3] # 时间差≥30秒,触发连续段断点检查 if (time_diff >= 30) { # 当前连续段长度≥3,输出段内所有记录 if (seg_len[$3] >= 3) { for (i=1; i<=seg_len[$3]; i++) print seg_cache[$3,i] # 若需要仅输出每个firm的第一个符合条件段,取消下一行注释即可 # output_done[$3] = 1 } # 清空连续段缓存,开始新段统计 seg_len[$3] = 0 delete seg_cache[$3] } } # 该firm已输出过符合要求的段,直接跳过后续缓存逻辑 if (output_done[$3]) { last_sec[$3] = cur_sec next } # 当前记录加入连续段缓存 seg_len[$3]++ seg_cache[$3, seg_len[$3]] = $0 last_sec[$3] = cur_sec } # 遍历结束后检查所有firm最后一段未触发断点的缓存 END { for (f in firm_cnt) { if (output_done[f]) continue if (seg_len[f] >= 3) { for (i=1; i<=seg_len[f]; i++) print seg_cache[f,i] } } } ' orders.csv orders.csv
逻辑说明
- 双遍历逻辑和已实现的firm计数逻辑一致,第一遍仅做分组计数,第二遍才做实际过滤处理
- 时间差计算严格按firm分组独立统计,不会被其他firm的记录打断连续段计算
- 默认输出所有符合长度要求的连续段,如需仅输出第一个符合段,按注释打开对应行即可
- 所有计算基于秒级时间戳,不存在跨小时、跨分钟的计算错误
内容的提问来源于stack exchange,提问作者Ad Il
相关产品推荐
相关产品推荐

