使用 AWK 合并两个文本文件

使用 AWK 合并两个文本文件

我对 awk 没有太多经验,所以我很难克服它的一个问题。我有两个名为 file1.txt 和 file2.txt 的文件。文件1.txt:

20 101 1 2 3 4
20 102 5 6 7 8
20 108 3 3 3 3

文件2.txt:

20 100 99 99 99 99
20 101 11 22 33 44
20 103 55 66 77 88

每个文件中前两列之后始终有 4 个值。

我想做的是将这些文件合并为一个。我将通过第一列和第二列加入他们。

生成的文件中应有 10 列。前两列是关键列,接下来的 4 列是第一个文件中的值,最后 4 列来自第二个文件。

在生成的文件中,第一个文件中与第二个文件不匹配的每条记录(反之亦然)将具有表示缺失值的附加零。

一切都由空格字符分隔。

结果应该是这样的:

20 100 0 0 0 0 99 99 99 99
20 101 1 2 3 4 11 22 33 44
20 102 5 6 7 8 0 0 0 0
20 103 0 0 0 0 55 66 77 88
20 108 3 3 3 3 0 0 0 0

这是我的 awk 脚本,是我根据在网上搜索时找到的脚本进行修改的:

BEGIN {                                                                                                                
   OFS=" "
}                                      
{                               
   i=$1 OFS $2 #Making key out of first and second field of the first file                    
}
   NR==FNR {                             
   A[i]=$0  #Saving records from first file to an array using first two columns as index                           
   next
}
#Next part assumes that I'm reading file2.txt                                         
i in A {                                
   printf "%s",A[i]  #Here, I have a match with first file, and I want to print the joined record I saved from file1.txt                                                                                               
   print $3,$4,$5,$6 #In order to print a joined record, after printing record from first file, I'm printing columns from the second file                                                                                           
   delete A[i]                           
   next
}

{ #Here I print records from file2.txt that don't have a match with file1.txt, and put zeroes to fill missing values
   print 0,0,0,0,$3,$4,$5,$6
}
END { #In the END block I'm printing everything from file1.txt that doesn't have a match and print zeroes aftewards to fill missing values
   for (i in A) {  printf "%s",A[i]; print 0,0,0,0  }                           
}

结果按第二列排序,所有缺失值均用零填充。但是,我目前得到的结果如下所示:

20 100 0 0 0 0 99 99 99 99
11 22 33 443 4
20 103 0 0 0 0 55 66 77 88
20 108 3 3 3 3 0 0 0 0
0 0 0 0 6 7 8

尽管文件没有排序(我总是可以使用 sort -k 2),但有些行没有按照我预期的方式打印,而且我无法解释为什么它不能正常打印 A 的元素大批。我尝试过各种方法,例如暂时更改 ORS (根本没有输出)或使用 print 而不是 printf (结果看起来也很奇怪)。

由于缺乏经验,这引发了一些额外的问题:

使用awk来完成这个任务是否合理?我尝试过使用加入,但最终陷入困境,因为它无法打印末尾带有换行符的列。也许 Python 脚本会更有用?

考虑到我将使用非常大的文件进行合并,在内存方面使用数组是否合理?

提前致谢!

答案1

awk '!second { file1vals[$1 FS $2]=$0 }
      second { print (($1 FS $2 in file1vals)?file1vals[$1 FS $2]: $1 FS $2 FS "0 0 0 0") FS $3, $4, $5, $6;
               delete file1vals[$1 FS $2]
             }
END{ for(x in file1vals) print file1vals[x], "0 0 0 0" }' file1 second=1 file2

只要有足够的内存来加载第一个,这就会起作用文件1进入记忆。

在第一个块中!second {...},它仅在它是第一个文件并且我们加载时运行文件1放入第一列和第二对上的关联数组中作为数组的键。

在第二个块中second {...},它仅在第二个文件时运行,我们打印两个文件中具有匹配键的连接行,否则我们打印键和 0,后跟其余列文件2;然后我们还从delete file1vals[$1 FS $2]两个文件中都存在密钥的数组中删除密钥。

在末尾的最后一个块中,我们打印与以下内容相关的剩余不匹配键文件1

相关内容