如何使用Awk将同组键值对多行数据聚合转换为CSV格式?
使用Awk将键值对行流聚合为CSV格式
针对这种每行包含多组「字段名 字段值」的行流数据,我们可以用Awk编写脚本自动聚合同一主体的分散数据,转换为标准CSV格式。以下是具体实现方案:
完整Awk脚本
BEGIN { OFS = "," field_idx = 0 } # 解析每行的键值对,处理带引号的字段 { i = 1 curr_key = "" curr_val = "" rec_id = "" while (i <= NF) { # 处理带引号的字段(字段名或值含空格的情况) if ($i ~ /^"/) { quoted_str = $i i++ while (i <= NF && $i !~ /"$/) { quoted_str = quoted_str " " $i i++ } quoted_str = quoted_str " " $i gsub(/^"|"$/, "", quoted_str) # 移除首尾引号 if (curr_key == "") { curr_key = quoted_str } else { curr_val = quoted_str } } else { # 处理普通无引号字段 if (curr_key == "") { curr_key = $i } else { curr_val = $i } } # 键值对完整时,存储数据 if (curr_key != "" && curr_val != "") { # 记录所有字段名,去重并按出现顺序保存 if (!(curr_key in field_map)) { field_map[curr_key] = ++field_idx fields[field_idx] = curr_key } # 生成聚合用的唯一记录ID(这里用Company+Name组合,确保同一人/主体的行被聚合) if (curr_key == "Company") { rec_id = curr_val } else if (curr_key == "Name") { rec_id = rec_id "|" curr_val } # 保存当前键值对到对应记录 data[rec_id, curr_key] = curr_val # 重置临时变量 curr_key = "" curr_val = "" } i++ } # 记录唯一的记录ID,避免重复输出 if (rec_id != "" && !(rec_id in rec_map)) { rec_map[rec_id] = 1 rec_list[++rec_cnt] = rec_id } } END { # 输出CSV表头 for (i = 1; i <= field_idx; i++) { # 含空格的字段名用引号包裹,符合CSV规范 printf "%s%s", (fields[i] ~ / / ? "\"" fields[i] "\"" : fields[i]), (i < field_idx ? OFS : "\n") } # 输出每条聚合后的记录 for (r = 1; r <= rec_cnt; r++) { rec_id = rec_list[r] for (i = 1; i <= field_idx; i++) { field = fields[i] val = data[rec_id, field] # 含空格的字段值用引号包裹 printf "%s%s", (val ~ / / ? "\"" val "\"" : val), (i < field_idx ? OFS : "\n") } } }
使用方法
- 将上述脚本保存为
aggregate_to_csv.awk文件。 - 假设输入数据文件名为
input.txt,执行以下命令生成CSV:
awk -f aggregate_to_csv.awk input.txt > output.csv
脚本关键逻辑说明
- 字段解析:专门处理带引号的字段(比如
"Favorite Book"或"The Hobbit"),确保含空格的字段名/值被正确识别,不会被空格分割成多个部分。 - 聚合依据:用
Company和Name的组合作为唯一记录ID,确保同一主体的分散行数据被聚合到同一行。如果需要调整聚合规则,修改生成rec_id的逻辑即可。 - CSV规范兼容:自动为含空格的字段名/值添加双引号,符合标准CSV格式要求。
- 动态表头:自动收集所有出现过的字段名作为表头,无需预先指定字段列表。
运行后,你提供的示例输入会生成目标格式的CSV文件。
内容的提问来源于stack exchange,提问作者user3310334
相关产品推荐
相关产品推荐

