使用Awk基于前三列共同行合并两个制表符分隔文本文件
解决两个制表符文件按前三列匹配合并的问题
你的需求是找到两个文件中前三列完全一致的行,然后将这些行成对输出(保留各自的后续列)。先看看你原来的awk代码哪里出问题了:
原代码的问题
- 字段分隔符设置错误:你直接写
awk FS=OFS='\t'的语法不对,应该在BEGIN块里统一设置输入输出的制表符分隔,否则awk无法正确识别制表符分隔的字段。 - 逻辑判断完全偏离需求:
$1 = $1, $2= $2, $3=$3是赋值操作,不是判断前三列是否匹配的条件,而且你没有对两个文件的行做关联存储,自然找不到匹配的行对。 - 硬编码列数不合理:你写死了要输出到
$19,但两个文件的列数不一致(第一个文件是10列,第二个是11-12列),这样会导致输出多余空字段或者截断有效内容。
正确的Awk解决方案
我们可以用关联数组存储第一个文件的行,以前三列的组合作为唯一键,然后遍历第二个文件时检查键是否存在,存在就输出对应的两行:
BEGIN { FS = OFS = "\t" # 统一设置输入输出为制表符分隔 } # 处理第一个文件:用前三列拼接成键,存储整行内容 NR == FNR { key = $1 OFS $2 OFS $3 lines[key] = $0 next } # 处理第二个文件:检查当前行的键是否在第一个文件的记录里 { key = $1 OFS $2 OFS $3 if (key in lines) { print lines[key] # 先输出第一个文件的对应行 print $0 # 再输出当前第二个文件的行 } }
把这段代码保存为merge.awk,然后运行命令:
awk -f merge.awk infile1.txt infile2.txt > out.txt
代码解释
NR == FNR:这个条件仅对第一个文件生效(NR是全局记录数,FNR是当前文件的记录数,第一个文件两者相等),我们把每一行的前三列拼接成唯一标识键,将整行内容存入关联数组lines。- 处理第二个文件时,同样生成键,如果该键存在于
lines数组中,说明找到了匹配行,就按要求输出第一个文件的对应行和当前行。
验证结果
用你提供的示例文件测试,输出会和你期望的完全一致:
chr9 35689814 35689922 U2OS_Noco_input_peak_1972 77 . 4.84893 12.13092 7.77385 26 chr9 35689814 35689922 TPM2 0 - 35689814 35691017 0 6 83,86,96,105,108,1203, chr9 35748701 35748740 U2OS_Noco_input_peak_1974 197 . 10.68892 24.88541 19.76040 127 chr9 35748701 35748740 GBA2 0 - 35748701 35749983 0 5 223,269,514,524,276, chr9 85677944 85678064 U2OS_Noco_input_peak_1980 44 . 3.93263 8.45104 4.42192 5 chr9 85677944 85678064 RASEF 0 - 85677782 85678092 0 2 261,310, 0,0,
内容的提问来源于stack exchange,提问作者user7249622
相关产品推荐
相关产品推荐

