CSVのフィールドに重複した値を持つ連続行を削除し、最後の行を保持します。

CSVのフィールドに重複した値を持つ連続行を削除し、最後の行を保持します。

次のような連続した重複エントリを含む2つの列を持つ非常に長いCSVファイルがあります。

...
1500,1533
1554,1678
1554,1703
1554,1728
1593,1766
...

最後の項目を除くすべての重複項目を削除する必要があります。したがって、上記の例の出力は次のようになります。

...
1500,1533
1554,1728
1593,1766
...

また、ファイルの残りの行を元の順序で維持する必要があります。

頑張ったtac file.csv | sort -k1,1 -r -u -t,

ただし、これは予想される結果を提供せず、ソートベースの機能は私の行の順序を混乱させます。

答え1

そしてsed

sed '$!N;/\(.*,\).*\n\1/!P;D' infile

Nすなわち、パターン空間には常に2つの連続するラインがあり、sed Pそのうちの第1のラインは、そのラインの第1のフィールドが第2のラインの第1のフィールドと異なる場合にのみ印刷される。次に、Dパターン空間から最初の行を削除し、ループを再開します。


別の方法はgnu datamash(ファイルがdatamashソートされるべき入力に従ってソートされていると仮定):

datamash -t ',' -g 1 last 2 <infile

これにより、g区切られた入力がstフィールドにグループ化され、各グループの値(nd列から)のみが印刷されます。,1last2


ファイルがソートされていない場合は、次のdatamash基準でソートできます-s

datamash -t ',' -s -g 1 last 2 <infile

ただし、これは行の初期順序が維持されないことを意味します。したがって、望ましい効果がないかもしれません。この場合、sed//awkなどを使用できますperl

答え2

awkに代わるものもあります:

 awk -F, 'NR==1{old=$0;check=$1}NR>1 && $1 != check {print old}{old=$0;check=$1}END{print old}' knovice
1500,1533
1554,1728
1593,1766

答え3

別の方法がありますawk(ありがとうございます@グレン):

 tac file | awk -F, 'awk -F, '!seen[$1]++' | tac

区切り記号を設定します-F,。でawk式がtrueと評価されている場合、デフォルトのアクションは現在の行を印刷することです。!seen[$1]配列に最初のフィールドがない場合はtrueですseen。しかし、私たちもそれを作ったので、seen[$1]++初めて見たときだけ間違っています。その結果、最初のコピーのみが印刷されます。

上記のスクリプトは、繰り返し実行されるたびに最後のスクリプトの代わりに最初のスクリプトを保持するため、これら2つの呼び出しは順序をtac反転して最後のスクリプトを維持するための醜いハッキングです。 2つなので最終順番は変わりません。

答え4

Miller(mlr)を使用して最初のフィールドにグループ化しながら、各グループの最後の項目を取得します。

$ mlr --csv -N tail -n 1 -g 1 file
1500,1533
1554,1728
1593,1766

上記のコマンドで簡単に変更すると、最後の2つが得られますtail -n 1tail -n 2

関連情報