Bash/Shell: как удалить дубликаты из CSV-файла по столбцам?

У меня есть csv, разделенный ;. Мне нужно удалить строки, в которых содержимое 2-го и 3-го столбца не уникально, и вывести материал на стандартный вывод.

Пример ввода:

irrelevant;data1;data2;irrelevant;irrelevant  
irrelevant;data3;data4;irrelevant;irrelevant  
irrelevant;data5;data6;irrelevant;irrelevant  
irrelevant;data7;data8;irrelevant;irrelevant  
irrelevant;data1;data2;irrelevant;irrelevant  
irrelevant;data9;data0;irrelevant;irrelevant  
irrelevant;data1;data2;irrelevant;irrelevant  
irrelevant;data3;data4;irrelevant;irrelevant  

Желаемый результат

irrelevant;data5;data6;irrelevant;irrelevant  
irrelevant;data7;data8;irrelevant;irrelevant  
irrelevant;data9;data0;irrelevant;irrelevant  

Я нашел решения, в которых на выходе печатается только первая строка:

sort -u -t ";" -k2,1 file  

Но этого недостаточно.

Я пытался использовать uniq -u, но не могу найти способ проверить только несколько столбцов.


person xpdude    schedule 22.08.2014    source источник
comment
во всех строках нет уникального значения во 2-м и 3-м столбцах.   -  person Avinash Raj    schedule 22.08.2014
comment
Я согласен с @jaypal, этот вопрос касается только поиска уникальных записей.   -  person anubhava    schedule 22.08.2014
comment
@AvinashRaj: OP хочет перечислить те записи, где col2, col3 появляется только один раз во всем файле.   -  person anubhava    schedule 22.08.2014
comment
О, спасибо @anubhava   -  person Avinash Raj    schedule 22.08.2014
comment
Да, @anubhava прав. Хранение материала во временном шаблоне кажется единственным выходом. Кажется, решения для awk и perl очень похожи.   -  person xpdude    schedule 23.08.2014


Ответы (3)


Использование awk:

awk -F';' '!seen[$2,$3]++{data[$2,$3]=$0}
      END{for (i in seen) if (seen[i]==1) print data[i]}' file
irrelevant;data5;data6;irrelevant;irrelevant
irrelevant;data7;data8;irrelevant;irrelevant
irrelevant;data9;data0;irrelevant;irrelevant

Объяснение: Если комбинация $2,$3 не существует в массиве seen, то новая запись с ключом $2,$3 сохраняется в массиве data вместе со всей записью. Каждый раз, когда обнаруживается запись $2,$3, счетчик для $2,$3 увеличивается. Затем, в конце концов, эти записи с counter==1 печатаются.

person anubhava    schedule 22.08.2014

Если порядок важен и если вы можете использовать perl, то:

perl -F";" -lane '
    $key = @F[1,2]; 
    $uniq{$key}++ or push @rec, [$key, $_] 
}{ 
    print $_->[1] for grep { $uniq{$_->[0]} == 1 } @rec' file
irrelevant;data5;data6;irrelevant;irrelevant  
irrelevant;data7;data8;irrelevant;irrelevant  
irrelevant;data9;data0;irrelevant;irrelevant  

Мы используем column2 и column3 для создания составного ключа. Мы создаем массив массивов, нажимая клавишу и строку на массив rec для первого вхождения строки.

В блоке END мы проверяем, является ли это вхождение единственным вхождением. Если это так, мы идем дальше и печатаем строку.

person jaypal singh    schedule 22.08.2014

awk '!a[$0]++' file_input > file_output

Это сработало для меня. Он сравнивает целые строки.

person Andrey Strelnikov    schedule 24.03.2015