次のような連続した重複エントリを含む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列から)のみが印刷されます。,
1
last
2
ファイルがソートされていない場合は、次の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 1
。tail -n 2