Вопрос или проблема
У нас есть следующий текстовый файл, и что нам нужно сделать, так это поменять местами два столбца, если мы находим дублированный первый столбец; для каждого 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
Пояснение к коду:
found[$1]++;
: Эта строка отслеживает количество появлений каждого значения из первой колонки (IP-адреса) с помощью ассоциативного массиваfound
.if (found[$1] > 1)
: Проверяет, если текущее значение уже встречалось. Если да, то значит, это дубликат.buf=$1; $1=$2; $2=buf
: Выполняет обмен значениями между первой и второй колонками, сохраняя значение первой колонки во временной переменнойbuf
для обмена.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
Пояснение к коду:
BEGIN {$, = " "}
: Установка разделителя для вывода в пробел.scalar(grep {$_ eq $F[0]} @buf)
: Проверяет, существует ли текущее значение из первой колонки в массиве@buf
.print(reverse(@F))
: Если значение найдено (т.е. это дубликат), то происходит вывод колонок в обратном порядке.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-адресов в первой колонке. Вы можете выбрать любой из них в зависимости от ваших предпочтений и окружения, в котором вы работаете.