连接两个具有不同列数和行数的文件

连接两个具有不同列数和行数的文件

我有两个文件。 file_1.txt 看起来像这样:

R1     C1     C2     C3     C4     C5
R2     C1     C2     C3     C4     C5
R3     C1     C2     C3     C4     C5
R4     C1     C2     C3     C4     C5
R5     C1     C2     C3     C4     C5
R6     C1     C2     C3     C4     C5
R7     C1     C2     C3     C4     C5
R8     C1     C2     C3     C4     C5
R9     C1     C2     C3     C4     C5
R10    C1     C2     C3     C4     C5

file_2.txt 看起来像这样:

R4 C4 C5
R6 C4 C5
R7 C4 C5
R9 C4 C5

我想将 file_1.txt 中的 C4 和 C5 值替换为 file_2.txt 中对应的值,同时保持 file_1.txt 中的 C1、C2 和 C3 值不变。

因此生成的 file_3.txt 应如下所示:

R1     C1     C2     C3     C4     C5
R2     C1     C2     C3     C4     C5
R3     C1     C2     C3     C4     C5
R4     C1     C2     C3     C4_new C5_new
R5     C1     C2     C3     C4     C5
R6     C1     C2     C3     C4_new C5_new
R7     C1     C2     C3     C4_new C5_new
R8     C1     C2     C3     C4     C5
R9     C1     C2     C3     C4_new C5_new
R10    C1     C2     C3     C4     C5

所有值都是数字。 file_1.txt 和 file_2.txt 中的第一列是关键字段,按数字升序排序。

这是一个人加入就可以做的事情吗?

答案1

这个问题的典型应用是

awk 'NR == FNR{a1[$1]=$2; a2[$1]=$3; next};
    $1 in a1{$5=a1[$1]; $6=a2[$1]};{print}' file_2.txt file_1.txt     

您可能必须将输出字段分隔符显式设置为制表符,在这种情况下

awk -v OFS='\t' 'NR == FNR{a1[$1]=$2; a2[$1]=$3; next};
    $1 in a1{$5=a1[$1]; $6=a2[$1]};{print}' file_2.txt file_1.txt 

答案2

这并不能解决您的问题,而是向您展示为什么join名义上听起来它应该在这种特定情况下起作用,但事实并非如此。我花了相当多的时间试图join在这个网站上解决与您类似的问题,标题为:使用唯一标识符连接两个文件

第一种方法

解决您的问题的方法join如下:

$ join -a1 -1 1 -2 1 -o 1.1 1.2 1.3 1.4 2.2 2.3 <(sort file_1.txt) <(sort file_2.txt)
R10 C1 C2 C3  
R1 C1 C2 C3  
R2 C1 C2 C3  
R3 C1 C2 C3  
R4 C1 C2 C3 C4_new C5_new
R5 C1 C2 C3  
R6 C1 C2 C3 C4_new C5_new
R7 C1 C2 C3 C4_new C5_new
R8 C1 C2 C3  
R9 C1 C2 C3 C4_new C5_new

正如您所看到的,join需要将文件放入排序的形式,因此对于初学者来说,如果文件的原始顺序很重要,则此选项可能会造成问题。

此外,无法join根据列的值、存在值或缺少值来判断从一个文件或另一个文件有条件地打印列的值。

第二种方法

另一种方法join可能是这样的:

$ join -a1 -1 1 -2 1  <(sort file_1.txt) <(sort file_2.txt)
R10 C1 C2 C3 C4 C5
R1 C1 C2 C3 C4 C5
R2 C1 C2 C3 C4 C5
R3 C1 C2 C3 C4 C5
R4 C1 C2 C3 C4 C5 C4_new C5_new
R5 C1 C2 C3 C4 C5
R6 C1 C2 C3 C4 C5 C4_new C5_new
R7 C1 C2 C3 C4 C5 C4_new C5_new
R8 C1 C2 C3 C4 C5
R9 C1 C2 C3 C4 C5 C4_new C5_new

它再次接近您想要的,但不允许您使用任何条件逻辑从一个文件或另一个文件打印一列。

第三种方法

这个可行,但我们必须分解并获得一些外部帮助,以awk省略当其对应项存在于 中时会移位的尾随列file_2.txt

$ join -a1 -1 1 -2 1 -o 1.1 1.2 1.3 1.4 2.2 2.3 1.5 1.6 1.7 <(sort file_1.txt) <(sort file_2.txt) | awk '{$7=$8=""}1'
R10 C1 C2 C3 C4 C5  
R1 C1 C2 C3 C4 C5  
R2 C1 C2 C3 C4 C5  
R3 C1 C2 C3 C4 C5  
R4 C1 C2 C3 C4_new C5_new  
R5 C1 C2 C3 C4 C5  
R6 C1 C2 C3 C4_new C5_new  
R7 C1 C2 C3 C4_new C5_new  
R8 C1 C2 C3 C4 C5  
R9 C1 C2 C3 C4_new C5_new  

使用刚刚加入吗?

Join 的市场范围非常狭窄,它可以成为一个有用的工具。对于替换类型的问题(您的问题更符合该问题),诸如awkperl、 或 之类的工具sed会更适合。

相关内容