Найти дублирующееся значение столбца в CSV

Найти дублирующееся значение столбца в CSV

Я пытаюсь найти дубликаты идентификаторов в большом CSV-файле, в каждой строке есть только одна запись, но условием поиска дубликатов будет первый столбец.<id>,<value>,<date>

пример.csv

11111111,high,6/3/2019
22222222,high,6/3/2019
33333333,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

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

11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

Для вывода заказ не требуется.

решение1

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

awk -F, 'data[$1] && !output[$1] { print data[$1]; output[$1] = 1 }; output[$1]; { data[$1] = $0 }'

Он просматривает каждую строку и ведет себя следующим образом:

  • если мы уже видели значение в первом столбце, обратите внимание, что мы должны вывести любую строку, соответствующую ему, и вывести запомненную строку;
  • вывести текущую строку, если ее первый столбец совпадает с тем, который мы хотим вывести;
  • сохранить текущую строку, находящуюся в первом столбце.

решение2

Если все ваши идентификаторы имеют одинаковую длину (в вашем примере 8 символов), вы можете сделать все это с помощью sortGNU uniq:

$ sort file | uniq -Dw 8
11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

Если они разной длины, вы все равно можете использовать этот подход, но это немного сложнее:

$ tr ',' ' ' < file | sort  | rev | uniq -f2 -D | rev | tr ' ' ','
11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

решение3

awk -F, '$1 in m { print m[$1]$0; m[$1]=""; next } 
                 { m[$1]=$0 "\n" }' ex

решение4

Это можно сделать, GNU sedиспользуя его расширенные конструкции регулярных выражений. Сначала мы загружаем файл в пространство шаблона, а затем удаляем любые неповторяющиеся строки из начала пространства шаблона. Кроме того, \n\nв конце пространства шаблона размещается флаг, в котором мы перебрасываем повторяющиеся строки. Так что как только этот флаг поднимается до начала пространства шаблона => операция завершается, и теперь мы можем продолжить и удалить маркеры из пространства шаблона и вывести на stdout.

$ sed -Ee '
   $!{
      N;s/^/\n/
      $s/$/\n\n/;D
   }
   /^([^,\n]*),[^\n]*\n(.*\n)?\1,/!D
   s/^([^\n]*)(.*)/\2\1\n/;/^\n\n/!D
   s/^\n\n//;s/\n$//
' inp

Это POSIX-sedверсия И другой способ подхода к проблеме, когда мы не сохраняем весь файл в любой момент времени ни в шаблоне, ни в пространстве удержания. Как только появляется дубликат строки, он выводится на stdout И ссылка на строку помечается и выводится, помечается, потому что мы не хотим печатать ее в следующий раз, когда ее дубликат будет обнаружен.

$ sed -ne '
   H;g;y/\n_/_\n/
   /.*_\([^,_]*\)\(,[^_]*\)\[0]_\(.*_\)\{0,1\}\1,[^_]*$/{
      s//\1\2/;y/_\n/\n_/;p
      g;s/.*\n//p;g;y/\n_/_\n/
      s/\(.*_\([^,_]*\),[^_]*\)\[0]\(_\(.*_\)\{0,1\}\)\2,[^_]*$/\1[1]\3/
      s/_$//;y/_\n/\n_/;bh
   }
   /.*_\([^,_]*\)\(,[^_]*\)\[1]_\(.*_\)\{0,1\}\1,[^_]*$/{
      s/.*_//;y/_\n/\n_/;p
      g;s/\(.*\)\n.*/\1/;bh
   }
   y/_\n/\n_/;s/$/[0]/;:h;h
' inp

Это Perlрешение проблемы, где мы сохраняем строки в хэше массива. Как только мы видим повторяющуюся строку, мы печатаем массив и также очищаем его, а также печатаем дублирующуюся строку.

$ perl -F, -lane '
   push(@{$h{$F[0]}},$_),next if ! exists $h{$F[0]};
   print for splice(@{$h{$F[0]}}),$_;
' inp

Выход:

11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

Связанный контент