Text-Processing

uniq 一個忽略列的 csv 文件,可能是 awk 嗎?

  • September 17, 2013

給定這個文件(註釋不是文件的一部分,而是解釋的一部分)……

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 個文件。

目標:Debian GNU/Linux 7 amd64, 256MB / Xeon。

編輯:調整範例,因為欄位不是固定寬度,uniq --skip-chars=n據我所知,涉及的解決方案將不起作用。

使用awk,您可以執行以下操作:

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

最簡單的方法

sort -u -t, -k1,2 -k4
  • -u: 只輸出等號的第一行
  • -t,: 使用逗號作為欄位分隔符
  • -k1,2 -k4:僅對欄位 1,2 和 4 以及其餘欄位進行排序

另一種選擇是在兩側使用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 Guru 還很遠,所以很可能它可以以更優雅的方式完成 - 請參閱 Perl-like 的其他答案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};
}

引用自:https://unix.stackexchange.com/questions/91032