Как удалить строку, если она содержит шаблон только один раз во всем файле для определенного столбца

Я бы использовалawk:

awk 'NR==FNR{a[$0]++;next}a[$1]' file1 file2

где ваши идентификаторы находятся в файле1, а остальные — в файле2. Выход:

1 96 283 4
3 57 294 0
3 24 284 0
8 19 239 78
8 18 289 90
-2
01.02.2021, 17:04
2 ответа
awk '
  !B {a[$1]++}
  B && a[$1] > 1
' B=0 file B=1 file

Получите первое поле (= ID )и отсортируйте его, а затем уникализируйте идентификаторы и сохраните только дубликаты. Передайте их xargs и создайте регулярное выражение egrep ERE из каждого такого идентификатора.

< file \
  cut -d" " -f1          \
| sort  | uniq -d        \
| xargs -I{} echo ^{}\\s \
| grep -Ef - file        \
;

Используя perl, мы глотаем опцию файла -0777и запускаем регулярное выражение через запись, и если в каждой строке, начинающейся ^, мы можем увидеть первое поле (= ID )ниже или идентификатор уже встречался ранее, напечатайте текущую строку

perl -0777ne '
  () = m/(?msx)
      ^
      (?<line>
        (?<ID> A\w+)
        \h.*?\n
      )

      (?=
        (?:.*?\n)?
        (?<lukahead> \g{ID}|$)
      )

      (?{ my %seen;
        my($id_visible_ahead, $id_already_seen) =
          map { $_ > 0 } 
length($+{lukahead}), $seen{$+{ID}};

        print($+{line}),$seen{$+{ID}}++
          if $id_visible_ahead || $id_already_seen;
      })
   /g;
' file

Выход:

A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
0
18.03.2021, 22:33

Во-первых, будут возвращены все повторяющиеся идентификаторы, которые вы хотели бы сохранить.:

$ awk '{ print $1 }' <file | sort | uniq -d
A2SGWS7CUGU8GB

Он делает это, извлекая первое поле с разделителями -пробелами, идентификатор, используя awk. Затем он сортируется, и uniq -dиспользуется для вывода только дублирующихся идентификаторов.

Затем мы можем использовать эти (единичные, в данном случае )идентификаторы, для извлечения соответствующих строк из исходного файла, который необходимо сначала отсортировать, используяjoin:

$ join <( awk '{ print $1 }' <file | sort | uniq -d ) <( sort file )
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB

Если ваша оболочка не поддерживает подстановку процессов с использованием <(...), вы можете сделать это в два -шага, используя временный файл:

$ sort -o file.sorted file
$ awk '{ print $1 }' <file | sort | uniq -d | join - file.sorted
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB

Используя только awk, это можно сделать следующим образом:

$ awk 'NR == FNR { count[$1]++; next } count[$1] > 1' file file
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB

Обратите внимание, что файл дважды упоминается в командной строке, так как он дважды считывается кодом awk.

В первый раз ассоциативный массив countзаполняется количеством просмотров каждого ID, а во второй раз выводится каждая строка, которая имеет ID, который был просмотрен более одного раза.

Разница между двумя описанными выше подходами заключается в том, что команда awk, представленная последней, сохраняет порядок исходных данных, но потребляет память, пропорциональную количеству уникальных идентификаторов. Первый подход будет генерировать отсортированные результаты и может быть более подходящим для очень больших данных.


Для сохранения строки заголовка команды нужно немного изменить:

$ join <( awk '{ print $1 }' <file | sort | uniq -d ) <( sort file ) | cat <(head -1 file) -

или

$ sort -o file.sorted file
$ awk '{ print $1 }' <file | sort | uniq -d | join - file.sorted > file.noheader
$ head -1 file | cat - file.noheader

или

$ awk 'NR == 1 ; NR == FNR { count[$1]++; next } count[$1] > 1' file file
1
18.03.2021, 22:33

Теги

Похожие вопросы