Есть ли способ стереть все дубликаты в файле и подсчитать, сколько дубликатов существует, сохраняя при этом исходный порядок файлов

#linux #shell #text #command-line #archlinux

#linux #оболочка #текст #командная строка #archlinux ( архлинукс )

Вопрос:

У меня есть такой файл, как этот

 2/2
2/2
2/2
3/3
1/1
1/1
2/2
1/1
3/3
 

и т.д..

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

 4 2/2
2 3/3
3 1/1
 

Я попытался

 sort myfile.txt | uniq -c
 

но это возвращает вывод, подобный этому, и не сохраняет его в порядке первого экземпляра в файле

 2 3/3
4 2/2
3 1/1
 

Я также попробовал просто uniq -c сам по себе, но это не устраняет все дубликаты. Я использую Arch Linux на самом последнем ядре, поэтому мне нужны команды для этого.

Извините, что это было так запутанно, но любая помощь была бы признательна 🙂

Ответ №1:

Что-то вроде этого будет работать:

 awk '
  # This first line simply ensures that `order` is an array
  BEGIN {delete order[0]}
  ! ($1 in seen) {order[length(order) 1] = $1}
  {seen[$1]  } 
  END {for (i in order) print seen[order[i]], order[i]}
' data.txt
 

В этом скрипте мы поддерживаем два ассоциированных массива («словари» или «хэши» на других языках).:

  • order записывает порядок, в котором мы встречаем новые значения, и
  • seen записывает, сколько раз мы видели определенное значение

После обработки данных мы выполняем итерацию order , чтобы получить значения в том порядке, в котором они появились, и ищем их количество в seen массиве.

Учитывая ваш пример ввода, это приводит к:

 4 2/2
2 3/3
3 1/1
 

Комментарии:

1. Альтернативная реализация: !seen[$1] {order[n ] = $1} затем в КОНЕЧНОМ блоке for (i=0; i<n; i ) ... — цикл с for (i in a) , я полагаю, не гарантирует порядок индексов.

Ответ №2:

Используйте этот однострочный Perl:

 perl -lne 'push @order, $_ if !$seen{$_}  ; END { print "$seen{$_} $_" for @order; }' in_file
 

Однострочник Perl использует эти флаги командной строки:
-e : Указывает Perl искать код в строке, а не в файле.
-n : Перебирайте ввод по одной строке за раз, присваивая ему значение $_ по умолчанию.
-l : Удалите разделитель строк ввода ( "n" по * NIX по умолчанию) перед выполнением кода в строке и добавьте его при печати.

Массив @order сохраняет входные строки в порядке ввода, только первое вхождение каждой строки (благодаря if !$seen{$_} условию). Хэш %seen содержит уникальные входные строки в качестве ключей и количество вхождений в качестве значений.

END { ... } Блок печатает содержимое хэша %seen в порядке, указанном во входных данных (благодаря @order ).

СМОТРИТЕ ТАКЖЕ:
perldoc perlrun : как выполнить интерпретатор Perl: переключатели командной строки