Найти уникальные строки, игнорируя определенные столбцы

В оболочке, если у вас установлен Perl rename (иногда называемый prename):

rename -v 's/$/.bad/' *

Если у вас слишком много файлов для shell * glob, чтобы обработать их все, вы можете смешать их с помощью find следующим образом (также замените + на \;, если необходимо):

find . -maxdepth 1 -exec rename -v 's/$/.bad/' {} +

Для Perl просто используйте move из стандартного модуля:

use File::Copy;
for (<*>) { move($_, "$_.bad"); }
-1
16.11.2018, 21:36
1 ответ

Посылка :это скорее доказательство концепции, чем реальное решение, позиционирующее себя где-то между неэлегантным и совершенно уродливым.

Ваши требования мне не совсем понятны, поэтому вот мои предположения:

  • Вы хотите выделить все и только те строки, которые имеют уникальную комбинацию подмножества их столбцов (1, 3 и 4 ). Если вас интересует что-то другое -, скажем, только в парах строк (не больше и не меньше двух )с одинаковыми значениями для двух столбцов и разными значениями для третьего столбца -, пожалуйста, обновите свой вопрос. чтобы было понятно.
  • Вы хотите распечатать все содержимое выбранных строк (всех шести столбцов ).
  • Поля в ваших строках разделены табуляцией --, а не пробелом -. (В противном случае это было бы немного странно, так как ваш пятый столбец, похоже, содержит пробельные символы ). Этот метод необходимо будет адаптировать к различным разделителям полей.

В этом коде (замените два вхождения your_fileфактическим именем файла):

grep -f \
<(sort -k 1b,1b -k 3n,3n -k 4n,4n your_file |
  nl -n rz -w 9 |
  cut -f 1,2,4,5 |
  uniq -f 1 -c |
  grep '^[[:space:]]*1' |
  sed 's/\(^[[:space:]]*1[[:space:]]*\)\(.*\)/^\2/' |
  cut -f 1) \
<(sort -k 1b,1b -k 3n,3n -k 4n,4n your_file |
  nl -n rz -w 9) |
  sed 's/\(^[0-9]\+[[:space:]]*\)\(.*\)/\2/'
  • Ваш файл отсортирован по столбцам 1, 3 и 4 (вероятно, не нужно, так как вы сказали в своем вопросе, что уже сделали это ).
  • Отсортированные строки нумеруются :начальными числами фиксированной длины 9 -символов, дополненными нулями -.
  • cutизвлекает только поля дерева, которые вы хотите сравнить, плюс первое (номер строки ).
  • uniqподсчитывает дубликаты для каждой результирующей строки, игнорируя первое поле (номер строки ), и добавляет счетчик к началу каждой строки.
  • grepвыбирает только те строки, количество которых равно 1.
  • sedудаляет счетчик с начала каждой результирующей строки.
  • cutизвлекает только первое поле, т.е.номер строки (таким образом проще, чем избегать предыдущего sedи пытатьсяcut -f 2).
  • grepиспользует результирующий набор номеров строк для фильтрации начального набора пронумерованных строк.
  • Окончательный sedудаляет номер первой строки из отфильтрованного набора строк.

Используя 14 строк вашего вопроса в качестве входных данных, он дает:

NZ_CP020102     B4U62_RS00155   30317   31869   16S ribosomal RNA       NCIB3610a
NZ_CP020102     TESTGENOMECL_31 30317   31870   16S ribosomal RNA       TESTGENOME

Примечания:
Вы можете использовать export LC_ALL=Cперед запуском этого кода, чтобы избежать проблем при сортировке некоторых символов.
Протестировано в Linux с помощью bashи инструментов GNU.

1
28.01.2020, 05:09

Теги

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