私は 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。