如何使用awk按首字段合并多行指定字段并实现去重排序
问题场景
现有分号分隔的文本文件data.file,需按每行第一个字段为分组键合并重复行,规则如下:
- 同组第2字段:剔除重复值、排序后用短横线
-连接 - 同组第3字段:取值固定,直接保留
- 同组第4字段:剔除重复值、按数值升序排序后用短横线
-连接 - 同组第5字段:仅保留首次出现的取值
原有使用getline逐行拼接的awk逻辑未做分组、去重、排序处理,存在行串行、值重复、顺序错乱问题,无法得到预期结果。
正确awk实现代码
awk -F';' ' !seen[$1]++ { lang[$1] = $3 status[$1] = $5 order[++total] = $1 } { col2[$1,$2] = 1 col4[$1,$4+0] = 1 } END { for (i=1; i<=total; i++) { city = order[i] # 处理第2字段 delete c2_arr c2_cnt = 0 for (key in col2) { split(key, tmp, SUBSEP) if (tmp[1] == city) c2_arr[++c2_cnt] = tmp[2] } asort(c2_arr) c2_str = arr_join(c2_arr, c2_cnt, "-") # 处理第4字段 delete c4_arr c4_cnt = 0 for (key in col4) { split(key, tmp, SUBSEP) if (tmp[1] == city) c4_arr[++c4_cnt] = tmp[2] + 0 } asort(c4_arr, "@val_num_asc") c4_str = arr_join(c4_arr, c4_cnt, "-") print city ";" c2_str ";" lang[city] ";" c4_str ";" status[city] } } function arr_join(arr, len, sep, res, idx) { res = arr[1] for (idx=2; idx<=len; idx++) res = res sep arr[idx] return res } ' data.file
逻辑说明
- 逐行遍历阶段:
- 用
seen数组标记分组是否首次出现,首次出现时记录该组第3、第5字段的取值,同时记录分组首次出现的顺序,保证最终输出顺序和原文件一致 - 利用awk关联数组的键唯一性自动对第2、第4字段去重,无需额外编写重复判断逻辑
- 用
- 收尾处理阶段:
- 按记录的分组顺序逐个处理每个城市的字段
- 第2字段按字符串规则排序,第4字段指定按数值升序排序,避免字符串排序导致
99排在33前面的问题 - 自定义数组拼接函数,将排序后的字段值用
-连接 - 按要求的分号分隔格式拼接输出
运行结果
执行上述代码后将输出完全符合预期的结果:
Istanbul;J;TK;13;OK London;C-K;EN;28-32;OK Paris;A-B;FR;30-40;OK Zurich;G-H;DE;33-82-99;OK
内容的提问来源于stack exchange,提问作者Andrés Chandía
相关产品推荐
相关产品推荐

