AWK を使用して 2 つのテキスト ファイルを結合する

AWK を使用して 2 つのテキスト ファイルを結合する

私は awk の経験があまりないので、awk に関する 1 つの問題を克服するのに苦労しています。file1.txt と file2.txt という名前の 2 つのファイルがあります。File1.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

各ファイルの最初の 2 列の後には、常に 4 つの値があります。

私がやろうとしているのは、これらのファイルを 1 つに結合することです。最初の列と 2 番目の列で結合します。

結果のファイルには 10 列あります。最初の 2 列はキー列、次の 4 列は最初のファイルからの値、最後の 4 列は 2 番目のファイルからの値です。

結果のファイルでは、最初のファイルから 2 番目のファイルと一致しないすべてのレコード (およびその逆) に、欠損値を表すゼロが追加されます。

すべては空白文字で区切られます。

結果は次のようになります。

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

これは、Web で検索中に見つけた 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  }                           
}

結果は 2 番目の列でソートされ、欠損値はすべてゼロで埋められます。ただし、現在取得している結果は次のようになります。

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 を変更したり (まったく出力されない)、printf の代わりに print を使用したり (結果も奇妙に見えます) など、さまざまなことを試しました。

経験不足のため、いくつかの追加の質問が生じます。

このタスクを完了するには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配列のキーとして1列目と 2列のペアに関連付けられた配列に追加します。

2番目のブロックはsecond {...}、2番目のファイルの場合のみ実行され、両方のファイルでキーが一致する結合行を出力します。それ以外の場合は、キーと0に続いて残りの列を出力します。ファイル2delete file1vals[$1 FS $2]; 次に、両方のファイルにキーが存在する配列からもキーを削除します。

ENDの最後のブロックでは、残りの一致しないキーを出力します。ファイル1

関連情報