Проверка на дубликаты строк и их обмен

Вопрос или проблема

У нас есть следующий текстовый файл, и что нам нужно сделать, так это поменять местами два столбца, если мы находим дублированный первый столбец; для каждого IP максимальное количество повторений – два. Можете помочь? Вот пример: нам нужно поменять местами 172.55.33.95 с 172.55.32.163, так как 172.55.32.163 является дубликатом предыдущего:

172.55.34.48 172.55.33.95
172.55.32.163 172.55.34.48
172.55.32.163 172.55.33.95

Это позволит сохранить уникальные записи, но мне нужно сохранить все строки
awk ‘prev && ($1 != prev) {print seen[prev]} {seen[$1] = $0; prev = $1} END {print seen[$1]}’ /tmp/new.txt

На Perl вы могли бы сделать:

perl -lae 'BEGIN {$, = " "} scalar(grep {$_ eq $F[0]} @buf) ? print(reverse(@F)) : do {print(@F); push(@buf, $F[0])}' input
  • -l: авто-удаляет и авто-добавляет разделитель полей записей по умолчанию (\n) перед и после каждой оценки скрипта, переданного в -e;
  • -a: авто-разделяет каждую строку по разделителю полей ввода по умолчанию ( ).

Скрипт установит разделитель выходных полей в , затем, для каждой строки, он проверит, сохранено ли первое поле уже в @buf.

Если это так, он развернет текущую запись и выведет её; иначе он выведет текущую запись и добавит первое поле в @buf.

% perl -lae 'BEGIN {$, = " "} scalar(grep {$_ eq $F[0]} @buf) ? print(reverse(@F)) : do {print(@F); push(@buf, $F[0])}' input
172.55.34.48 172.55.33.95
172.55.32.163 172.55.34.48
172.55.33.95 172.55.32.163

Ответ может быть таким простым, как эта программа на awk:

$ awk '{found[$1]++; if (found[$1]>1) {buf=$1; $1=$2; $2=buf}} 1' input.txt 
172.55.34.48 172.55.33.95
172.55.32.163 172.55.34.48
172.55.33.95 172.55.32.163

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

Для этого значение из первого столбца сохраняется в буфер, заменяется значением из второго столбца, а значение из второго столбца, в свою очередь, заменяется сохранённым значением. В конце текущая строка выводится с учётом всех изменений (если есть), что и означает, казалось бы, “блуждающий” 1.

Ответ или решение

Вопрос: проверка дублирующихся строк и их обмен.

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

Пример данных

Допустим, у нас есть следующий текстовый файл:

172.55.34.48 172.55.33.95
172.55.32.163 172.55.34.48
172.55.32.163 172.55.33.95

Решение с помощью awk

Вы можете использовать следующую команду awk, чтобы выполнить требуемый обмен колонок:

awk '{found[$1]++; if (found[$1] > 1) {buf=$1; $1=$2; $2=buf}} 1' input.txt

Пояснение к коду:

  1. found[$1]++;: Эта строка отслеживает количество появлений каждого значения из первой колонки (IP-адреса) с помощью ассоциативного массива found.
  2. if (found[$1] > 1): Проверяет, если текущее значение уже встречалось. Если да, то значит, это дубликат.
  3. buf=$1; $1=$2; $2=buf: Выполняет обмен значениями между первой и второй колонками, сохраняя значение первой колонки во временной переменной buf для обмена.
  4. 1: Специальное выражение 1 в awk является эквивалентом команды print, что указывает на вывод текущей строки.

Пример результата:

Для данных выше вывод будет выглядеть следующим образом:

172.55.34.48 172.55.33.95
172.55.32.163 172.55.34.48
172.55.33.95 172.55.32.163

Решение с помощью perl

Также можно использовать perl для достижения аналогичного эффекта:

perl -lae 'BEGIN {$, = " "} scalar(grep {$_ eq $F[0]} @buf) ? print(reverse(@F)) : do {print(@F); push(@buf, $F[0])}' input

Пояснение к коду:

  1. BEGIN {$, = " "}: Установка разделителя для вывода в пробел.
  2. scalar(grep {$_ eq $F[0]} @buf): Проверяет, существует ли текущее значение из первой колонки в массиве @buf.
  3. print(reverse(@F)): Если значение найдено (т.е. это дубликат), то происходит вывод колонок в обратном порядке.
  4. push(@buf, $F[0]): Если значение не найдено, оно сохраняется в массив @buf.

Ожидаемый результат:

Для тех же данных результат выполнения команды perl будет следующим:

172.55.34.48 172.55.33.95
172.55.32.163 172.55.34.48
172.55.33.95 172.55.32.163

Заключение

Оба методы — awk и perl — прекрасно справляются с задачей проверки и обмена дублирующихся IP-адресов в первой колонке. Вы можете выбрать любой из них в зависимости от ваших предпочтений и окружения, в котором вы работаете.

Оцените материал
Добавить комментарий

Капча загружается...