使用 Unix 和 Awk 比较两个文件

Nam*_*ata 4 bash sed awk

我需要使用 4 个字段(文件 1 的字段 1、2、4 和 5 与文件 2 的字段 1、2、4 和 5)比较两个文件 File1 和 File2(以空格分隔)。

逻辑:
如果文件 1 的第 1、2 和 4 列与文件 2 的第 1、2 和 4 列匹配,并且第 5 列不匹配,则来自文件 1 和文件 2 的行都连接起来重定向为输出。因此,输出文件仅包含 File1 和 File2 的第 1、2 和 4 列匹配而第 5 列不匹配的那些行。

文件1:

sc2/80         20      .        A       T         86       PASS     N=2     F=5;U=4
sc2/60         55      .        G       T         76       PASS     N=2     F=5;U=4 
sc2/68         20      .        T       C         71       PASS     N=2     F=5;U=4
sc2/24         24      .        T       G         31       PASS     N=2     F=5;U=4
Run Code Online (Sandbox Code Playgroud)

文件2:

sc2/80         20      .        A        C        80      PASS    N=2       F=5;U=4
sc2/60         55      .        G        C        72      PASS    N=2       F=5;U=4 
sc2/68         20      .        T        C        71      PASS    N=2       F=5;U=4 
sc2/10         24      .        T        G        31      PASS    N=2       F=5;U=4
sc2/40         59      .        T        G        31      PASS    N=2       F=5;U=4
sc2/24         24      .        A        G        38      PASS    N=2       F=5;U=4
Run Code Online (Sandbox Code Playgroud)

输出:

sc2/80         20      .        A       T        86      PASS     N=2      F=5;U=4
sc2/80         20      .        A       C        80      PASS     N=2      F=5;U=4

sc2/60         55      .        G       T        76      PASS     N=2      F=5;U=4 
sc2/60         55      .        G       C        72      PASS     N=2      F=5;U=4
Run Code Online (Sandbox Code Playgroud)

我是该领域的新手,感谢您的帮助。

slm*_*slm 8

您可以使用awk. 将以下内容放入脚本中script.awk

FNR == NR {
  f1[$1,$2,$4] = $0
  f1_c14[$1,$2,$4] = 1
  f1_c5[$1,$2,$4] = $5
  next
}  

f1_c14[$1,$2,$4] {
  if ($5 != f1_c5[$1,$2,$4]) print f1[$1,$2,$4];
}

f1[$1,$2,$4] {
  if ($5 != f1_c5[$1,$2,$4]) print $0;
}
Run Code Online (Sandbox Code Playgroud)

现在像这样运行它:

$ awk -f script.awk file1  file2
sc2/80         20      .        A       T         86       PASS     N=2     F=5;U=4
sc2/80         20      .        A        C        80      PASS    N=2       F=5;U=4
sc2/60         55      .        G       T         76       PASS     N=2     F=5;U=4 
sc2/60         55      .        G        C        72      PASS    N=2       F=5;U=4
Run Code Online (Sandbox Code Playgroud)

该脚本的工作原理如下。此块创建 3 个数组f1f1_c14、 和f1_c5f1包含数组中 file1 的所有行,使用 file1 中第 1、2 和 4 列的内容进行索引。f1_c14是另一个具有相同索引(1、2 和 4 的内容)且值为 的数组1。第三个数组使用与第一个 2 相同的索引,以及文件 1 中第 5 列的值。

FNR == NR {
  f1[$1,$2,$4] = $0
  f1_c14[$1,$2,$4] = 1
  f1_c5[$1,$2,$4] = $5
  next
} 
Run Code Online (Sandbox Code Playgroud)

下一个块是负责从第一文件的打印线,file1的条件下,该列的1,2,和4匹配从柱file2AND它将onlu从打印线file1,如果第5列file1file2不匹配。

f1_c14[$1,$2,$4] {
  if ($5 != f1_c5[$1,$2,$4]) print f1[$1,$2,$4];
}
Run Code Online (Sandbox Code Playgroud)

第三个块负责打印关联行,从file2数组f1file2的第 1、2 和 4 列的相应行开始。同样,它仅在第 5 列不匹配时才打印。

f1[$1,$2,$4] {
  if ($5 != f1_c5[$1,$2,$4]) print $0;
}
Run Code Online (Sandbox Code Playgroud)

例子

像这样运行上面的脚本:

$ awk -f script.awk file1  file2
sc2/80         20      .        A       T         86       PASS     N=2     F=5;U=4
sc2/80         20      .        A        C        80      PASS    N=2       F=5;U=4
sc2/60         55      .        G       T         76       PASS     N=2     F=5;U=4 
sc2/60         55      .        G        C        72      PASS    N=2       F=5;U=4 
Run Code Online (Sandbox Code Playgroud)

您可以使用该column命令稍微清理输出:

$ awk -f script.awk file1  file2 | column -t
sc2/80  20  .  A  T  86  PASS  N=2  F=5;U=4
sc2/80  20  .  A  C  80  PASS  N=2  F=5;U=4
sc2/60  55  .  G  T  76  PASS  N=2  F=5;U=4
sc2/60  55  .  G  C  72  PASS  N=2  F=5;U=4
Run Code Online (Sandbox Code Playgroud)

这个怎么运作?

FNR == NR

这利用了awk以特定方式循环文件的能力。在这里,我们循环遍历文件,当我们位于第一个文件的行上时file,我们希望从file1.

这个例子展示了FNR == NR当我们给它 2 个模拟文件时正在做什么。一个有 4 行,而另一个有 5 行:

$ awk 'BEGIN {print "NR\tFNR\tline"} {print NR"\t"FNR"\t"$0}' \
     <(seq 1 4) <(seq 1 5)
NR  FNR line
1   1   1
2   2   2
3   3   3
4   4   4
5   1   1
6   2   2
7   3   3
8   4   4
9   5   5
Run Code Online (Sandbox Code Playgroud) 其他街区

其他块,f1_c14[$1,$2,$4]并且f1[$1,$2,$4]仅当来自这些数组元素的值具有值时才运行。