次の形式の10-100k行のさまざまなテキストファイルがあります。
"2018-12-07 23:21:32",XX,99,ZZZ,250,REMOVED
"2018-12-07 23:25:17",XX,99,ZZZ,250,AVAILBLE
"2018-12-07 23:29:05",DD,11,AAA,250,REMOVED
"2018-12-07 23:30:00",CH,00,UUU,250,REMOVED
"2018-12-07 23:31:45",MM,33,OOO,250,REMOVED
"2018-12-07 23:46:41",XX,99,ZZZ,250,REMOVED
上記の例では、列2、3、4が同じ3つのレコード(XX、99、ZZZ - 行1/2/6)があることがわかります。最初の2行を削除し、最後の行のみを保持する必要があります。
希望の出力は以下の通りです。
"2018-12-07 23:29:05",DD,11,AAA,250,REMOVED
"2018-12-07 23:30:00",CH,00,UUU,250,REMOVED
"2018-12-07 23:31:45",MM,33,OOO,250,REMOVED
"2018-12-07 23:46:41",XX,99,ZZZ,250,REMOVED
非常に遅く、100k〜ラインのファイルに対してメモリエラーを発生させるPHPスクリプトがあります。
答え1
最後の項目だけを残してすべてを削除するよりも、一連の重複項目のうち最初の項目だけを残してすべてを削除する方が簡単です。次のように試すことができます。
$ tac file | awk -F, '!seen[$2 FS $3 FS $4]++' | tac
"2018-12-07 23:29:05",DD,11,AAA,250,REMOVED
"2018-12-07 23:30:00",CH,00,UUU,250,REMOVED
"2018-12-07 23:31:45",MM,33,OOO,250,REMOVED
"2018-12-07 23:46:41",XX,99,ZZZ,250,REMOVED
答え2
BEGIN { FS = "," }
FNR == NR {
if (seen[$2,$3,$4])
delete lines[seen[$2,$3,$4]]
lines[FNR]
seen[$2,$3,$4] = FNR
next
}
FNR in lines
プログラムはawk
同じファイルを2回読み取ることを期待しています。ファイルを初めて読み込むと、FNR == NR
ブロックのみが実行されます。lines
配列のキーとして出力する行番号を記憶します。 2番目、3番目、4番目の列の特定の組み合わせを持つ行がすでに表示されている場合は、最も近い行番号をキーとして挿入して前(ステートメント)delete
。
ファイルの2番目の解析中に何が起こるのかは、配列内の現在の行番号を検索することですlines
。見つかった場合は、その行を印刷します。
同じコードの「1行」バージョンを実行する例:
$ awk -F, 'FNR==NR { if(s[$2,$3,$4]) delete l[s[$2,$3,$4]]; l[FNR]; s[$2,$3,$4]=FNR; next}; FNR in l' file file
"2018-12-07 23:29:05",DD,11,AAA,250,REMOVED
"2018-12-07 23:30:00",CH,00,UUU,250,REMOVED
"2018-12-07 23:31:45",MM,33,OOO,250,REMOVED
"2018-12-07 23:46:41",XX,99,ZZZ,250,REMOVED