私はawkの経験があまりなく、問題を克服するのに苦労しています。 file1.txtとfile2.txtという2つのファイルがあります。ファイル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
各ファイルの最初の2列の後には常に4つの値があります。
私がしたいのは、これらのファイルを1つにマージすることです。私はそれらを列1と列2に結合します。
生成されたファイルには10個の列が必要です。最初の2列はキー列で、次の4列は最初のファイルの値、最後の4列は2番目のファイルの値です。
結果ファイル内の2番目のファイルと一致しない(またはその逆)、最初のファイルの各レコードには、欠落値を示す追加の0が含まれています。
すべての項目は空白文字で区切られます。
結果は次のようになります。
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 }
}
結果は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配列キーとして、最初と2番目の列のペアの連想配列に配置します。
second {...}
2番目のファイルがある場合にのみ実行される2番目のブロックは、2つのファイルの一致するキーを持つリンクされた行を印刷します。それ以外の場合は、キーと0を印刷してから残りの列を印刷します。ファイル2;その後、delete file1vals[$1 FS $2]
両方のファイルにキーが存在する配列からキーを削除します。
最後のブロックでは、次に関連する一致しない残りのキーを印刷します。ファイル1。