如何跨多个CSV文件匹配指定列并输出对应字段?
解决方案
优先使用awk实现多文件匹配逻辑,无需复杂的链式join操作,命令如下(适用于GNU awk,主流Linux发行版默认自带):
awk ' BEGIN { FS = "," OFS = "\t" # 表头按你的6个文件的方法名依次修改即可 print "Trait", "Marker", "Chr", "Pos", "Blink", "Farmcpu", "GLM", "File4方法名", "File5方法名", "File6方法名" } { # 以$3、$4、$5三列构造唯一匹配key key = $3 SUBSEP $4 SUBSEP $5 } # 处理第一个文件,存储公共输出字段和第一个文件的$6值 ARGIND == 1 { trait[key] = $2 marker[key] = $3 chr[key] = $4 pos[key] = $5 val[1][key] = $6 next } # 处理第2-6个文件,存储对应文件的$6值 ARGIND >= 2 && ARGIND <=6 { val[ARGIND][key] = $6 next } END { # 仅输出6个文件都匹配到的key for (k in trait) { if (val[1][k] && val[2][k] && val[3][k] && val[4][k] && val[5][k] && val[6][k]) { print trait[k], marker[k], chr[k], pos[k], val[1][k], val[2][k], val[3][k], val[4][k], val[5][k], val[6][k] } } } ' File1 File2 File3 File4 File5 File6 > 最终输出文件
非GNU awk兼容版本
如果你的环境不支持ARGIND变量,可以用以下兼容版本:
awk ' BEGIN { FS = "," OFS = "\t" print "Trait", "Marker", "Chr", "Pos", "Blink", "Farmcpu", "GLM", "File4方法名", "File5方法名", "File6方法名" file_cnt = 1 } # 每个文件的第一行触发文件计数+1(排除第一个文件的首行) FNR == 1 && NR != 1 { file_cnt++ } { key = $3 SUBSEP $4 SUBSEP $5 } file_cnt == 1 { trait[key] = $2 marker[key] = $3 chr[key] = $4 pos[key] = $5 val[1][key] = $6 next } file_cnt >=2 && file_cnt <=6 { val[file_cnt][key] = $6 next } END { for (k in trait) { if (val[1][k] && val[2][k] && val[3][k] && val[4][k] && val[5][k] && val[6][k]) { print trait[k], marker[k], chr[k], pos[k], val[1][k], val[2][k], val[3][k], val[4][k], val[5][k], val[6][k] } } } ' File1 File2 File3 File4 File5 File6 > 最终输出文件
之前join报错原因说明
POSIX标准的join命令一次仅支持合并2个文件,你一次性传入6个文件时,join仅识别前两个输入,字段规则里的3.6指向第三个文件就会抛出无效文件编号的错误。如果一定要用join实现,需要链式合并,每次合并两个并逐次指定输出字段,操作繁琐且扩展性差,更推荐上述awk方案。
内容的提问来源于stack exchange,提问作者Waqas Khokhar
相关产品推荐
相关产品推荐

