使用AWK实现类VLOOKUP功能:为CSV文件追加多列数据
AWK实现CSV按列匹配合并:完整方案与代码解析
问题背景
我有两个无表头、大小不超过1GB的CSV文件,具体示例如下:
File1.csv(4列)
1,75.10,"1","1" 2,12.01,"0","4" 4,26.57,"1","1" 3,100.94,"1","4"
File2.csv(4列)
1,"D",0,5 1,"F",0,5 1,"N",1,3 2,"D",1,8 2,"F",0,6 2,"N",3,0 4,"I",,5 4,"F",2,9
需求说明
当File2.csv的第1列与File1.csv的第1列匹配时,将File1.csv的第2、3、4列追加到File2.csv对应行的末尾,最终生成包含7列的New.csv。
预期输出(New.csv)
1,"D",0,5,75.10,"1","1" 1,"F",0,5,75.10,"1","1" 1,"N",1,3,75.10,"1","1" 2,"D",1,8,12.01,"0","4" 2,"F",0,6,12.01,"0","4" 2,"N",3,0,12.01,"0","4" 4,"I",,5,26.57,"1","1" 4,"F",2,9,26.57,"1","1"
现有代码解析
我作为AWK新手,试错写出了仅能追加File1.csv第2列的代码,但对其中的三元运算符不理解,代码如下:
awk -F "," 'FNR==NR {a[$1]=$2; next} {print $0","(($1 in a)?a[$1]:"NA")}' File1.csv File2.csv > New.csv
逐段解释
-F ",":指定AWK以逗号作为字段分隔符,把每行内容拆分成多个字段($1、$2...代表第1、第2...列)。FNR==NR:AWK的经典判断逻辑——FNR是当前正在处理的文件的行号,NR是全局累计行号。当处理第一个文件(File1.csv)时,两个行号相等,触发该代码块。a[$1]=$2:定义一个关联数组a,以File1.csv的第1列值作为数组索引,对应存储第2列的值。next:跳过当前行的后续处理逻辑,直接读取下一行,确保第一个文件的内容只被用来填充数组。{print $0","(($1 in a)?a[$1]:"NA")}:处理第二个文件(File2.csv)时执行此块:$0代表当前行的完整内容;- 三元运算符
(条件)?值1:值2:判断当前行第1列是否存在于数组a的索引中,如果存在,就取a[$1](即File1对应的第2列值),否则输出NA; - 最终把当前行内容和匹配到的值用逗号拼接后打印。
完整解决方案
要实现追加File1.csv第2、3、4列的需求,只需修改数组存储的内容,把单字段改成多字段组合:
awk -F "," -v OFS="," 'FNR==NR {a[$1] = $2 OFS $3 OFS $4; next} {print $0, ($1 in a ? a[$1] : "NA,NA,NA")}' File1.csv File2.csv > New.csv
关键修改点与解释
-v OFS=",":通过变量OFS(输出字段分隔符)指定输出时用逗号分隔字段,避免手动拼接逗号的麻烦,也更规范。a[$1] = $2 OFS $3 OFS $4:不再只存第2列,而是把第2、3、4列用输出分隔符拼接后存储到数组a中,确保匹配后能一次性追加三列。print $0, ($1 in a ? a[$1] : "NA,NA,NA"):AWK中用逗号分隔的参数会自动用OFS连接,所以$0和匹配到的三列内容会被自动用逗号拼接;如果没有匹配项,输出三个NA对应三列的位置(可根据需求调整默认值)。
核心概念梳理
- 关联数组:AWK中的数组是关联型的,支持用字符串(这里是CSV第1列的值)作为索引,非常适合存储键值对形式的匹配关系。
- FNR与NR:区分多文件处理的核心逻辑,第一个文件用来构建匹配字典,第二个文件用来做匹配追加。
- 三元运算符:简化版的
if-else判断,格式为(condition) ? true-value : false-value,适合在单行代码中快速实现条件分支。
内容的提问来源于stack exchange,提问作者mollc
相关产品推荐
相关产品推荐

