使用awk基于部分匹配合并不同文件的多列
用AWK实现基于列匹配的文件内容合并需求
需求说明
现有两个以\作为列分隔符的文件A和B,需完成以下操作:
- 保留文件B的原有内容
- 基于文件A第2列与文件B第1列完全匹配的基础上,结合文件A第1列与文件B第2列的大小写不敏感部分匹配(例如A匹配A?、Asd,C匹配c、CA等),为文件B新增一列
- 若文件A中有多条符合匹配条件的记录,新增列的内容用
;分隔 - 最终每行末尾需保留一个
\
示例文件
文件A
A\2022.10.10\note a A\2022.10.10\note b B\2022.10.14\note c A\2022.10.14\note d C\2022.10.15\note e
文件B
2022.10.10\A? 2022.10.14\B? 2022.10.14\a 2022.10.15\C 2022.10.15\D
期望输出
2022.10.10\A?\note a;note b\ 2022.10.14\B?\note c\ 2022.10.14\a\note d\ 2022.10.15\C\note e\ 2022.10.15\D\
AWK实现方案
脚本代码
创建merge.awk脚本文件,内容如下:
BEGIN { # 设置输入/输出列分隔符为\ FS = "\\" OFS = "\\" } # 处理第一个输入文件(文件A),构建匹配映射 NR == FNR { date = $2 a_col1_lower = tolower($1) note = $3 # 按日期和小写的A列1存储note,多条记录用;拼接 if (date_map[date][a_col1_lower] != "") { date_map[date][a_col1_lower] = date_map[date][a_col1_lower] ";" note } else { date_map[date][a_col1_lower] = note } next } # 处理第二个输入文件(文件B),匹配并输出结果 { b_date = $1 b_col2_lower = tolower($2) result_notes = "" # 遍历当前日期下所有A列1的小写值,检查是否满足部分匹配 for (a_col1 in date_map[b_date]) { if (index(b_col2_lower, a_col1) != 0) { result_notes = (result_notes == "") ? date_map[b_date][a_col1] : result_notes ";" date_map[b_date][a_col1] } } # 输出原有内容 + 匹配到的note + 空字符串(保证末尾的\) print $0, result_notes, "" }
运行命令
在终端执行以下命令:
awk -f merge.awk 文件A 文件B
也可以直接使用单行命令:
awk 'BEGIN{FS="\\";OFS="\\"} NR==FNR{date=$2;a=tolower($1);n=$3;if(date_map[date][a]!="")date_map[date][a]=date_map[date][a]";"n;else date_map[date][a]=n;next} {d=$1;b=tolower($2);r="";for(a in date_map[d]){if(index(b,a)!=0){r=(r=="")?date_map[d][a]:r";"date_map[d][a]}}print $0,r,""}' 文件A 文件B
逻辑说明
- 分隔符设置:通过
FS和OFS指定列分隔符为\,避免手动拆分/拼接字符串 - 文件A预处理:用二维数组
date_map按日期分组,存储每个小写化的A列1对应的note内容,自动拼接多条记录 - 文件B匹配处理:对每行B的记录,先转小写B列2,遍历对应日期下的所有A列1值,通过
index()函数判断是否包含匹配,最后拼接所有符合条件的note并输出 - 末尾
\保证:输出时添加空字符串,利用OFS自动在末尾补全\
内容的提问来源于stack exchange,提问作者Forky
相关产品推荐
相关产品推荐

