使用 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

相關內容