uniq列を無視するcsvファイル、おそらくawkでしょうか?

uniq列を無視するcsvファイル、おそらくawkでしょうか?

この記事を見ると(コメントは文書の一部ではなく説明の一部です)...

x,a,001,b,c,d,y
x,a,002,b,c,e,yy
x,bb,003,b,d,e,y
x,c,004,b,d,e,y
x,c,005,b,d,e,y   # nb - dupe of row 4
x,dd,006,b,d,e,y
x,c,007,b,d,e,y   # nb - dupe of row 4 and 5
x,dd,008,b,d,f,y
x,dd,009,b,d,e,y   # nb - dupe of row 6
x,e,010,b,d,f,y

...次のような出力を得たいです。

x,a,001,b,c,d,y
x,a,002,b,c,e,yy
x,bb,003,b,d,e,y
x,c,004,b,d,e,y
x,dd,006,b,d,e,y
x,dd,008,b,d,f,y
x,e,010,b,d,f,y

ファイルから3番目の列を削除してからファイルからuniqを実行し、残りの行の3番目の列の値が正しい場所に再度追加された場合は、上記の結果が得られます。

しかし、私は本当にそのようなことができる何かを思い出そうと努力しています。私はLinuxのテキスト処理ユーティリティについて学ぶ機会を歓迎しました。

パフォーマンス:ファイルが1MBを超えることは不可能に見え、1日に1つのファイルのみが生成されます。

対象: Debian GNU/Linux 7 amd64, 256MB/Xeon.

編集:フィールドが固定幅ではないため、例を適用すると、uniq --skip-chars=n関連する解決策がわかっている限り機能しません。

答え1

これにより、awk次のことができます。

awk -F, -vOFS=, '{l=$0; $3=""}; ! ($0 in seen) {print l; seen[$0]}'

答え2

最も簡単な方法:

sort -u -t, -k1,2 -k4
  • -u:次の最初の行のみを出力します。
  • -t,:フィールド区切り文字としてカンマを使用します。
  • -k1,2 -k4:1、2、4番フィールドと残りのフィールドのみを並べ替える

もう1つのオプションは、データを両側で並べ替えることですsed(GNUオプションを参照-r)。これを行うには、レコードがほとんど固定長でなければなりません。それ以外の場合は失敗します(ほとんど目立たない)。

sed -r       's/^([^,]+,[^,]+)(,[^,]+)(.*)$/\1\3\2/' \
    | sort \
    | uniq -w 12 \
    | sed -r 's/^([^,]+,[^,]+)(.*)(,[^,]+)$/\1\3\2/'

必要に応じて、sort数字で並べ替えるために最後に別の項目を追加できます(該当する-kオプションを使用して実行する必要がある並べ替えに基づいて選択 - 例:)sed -k3 -t,

たとえば、Perlでは、一意性を確認したい部分をハッシュ(フル行の値)のキーとして使用し、キーがまだ定義されていない場合にのみハッシュを挿入できます。これは間違いなくsed(or awk)を使用するよりも柔軟性があるだけでなく、より多くの書き込み機能を提供します(私はPerlの専門家から離れているので、よりエレガントな方法で行うことができます。)Perlと同様のPerlソリューションへの他の答えを参照してください)。

#!/usr/bin/perl
use strict;

my %lines;
while (<>) {
    (my $k1, my $v, my $k2) = /^([^,]+,[^,]+,)([^,]+)(,.*)$/;
    my $k = $k1 . $k2;
    if (!exists($lines{$k})) {
        $lines{$k} = $_;
    }
}

for my $k (sort(keys(%lines))) {
    print $lines{$k};
}

答え3

これを行う1つの方法は次のとおりですawk | sort | uniq | awk

awk -F, '{a=$1;$1=$3;$3=a;print}' file | sort -k 2 | uniq -f 1 | awk -v OFS=',' '{a=$1;$1=$3;$3=a;print}'

答え4

より簡単なPerlアプローチは次のとおりです。

perl -F"," -ane '$a=join(",",@F[0,1,3 .. $#F]); print unless $k{$a}; $k{$a}++' file

-aフィールドを@F配列に分割し、-F","フィールド区切り記号をに設定します,。入力ファイルの各行で-n指定されたスクリプトを実行することを示します。-e

アイデアは、配列スライス(配列の最後まで要素0、1、および3)を取得し、文字列($a)で連結し、その文字列をハッシュ(連想配列)参照として使用することです。その後、ハッシュキーが以前に表示されなかった場合にのみ、各行が印刷されます。

関連情報