Как получить только уникальные результаты без сортировки данных?

40
$ cat data.txt 
aaaaaa
aaaaaa
cccccc
aaaaaa
aaaaaa
bbbbbb
$ cat data.txt | uniq
aaaaaa
cccccc
aaaaaa
bbbbbb
$ cat data.txt | sort | uniq
aaaaaa
bbbbbb
cccccc
$

В результате мне нужно отобразить все строки исходного файла, удалив все дубликаты (не только последовательные), сохранив при этом исходный порядок операторов в файле .

Здесь, в этом примере, результат, который я на самом деле искал, был

aaaaaa
cccccc
bbbbbb

Как я могу выполнить эту обобщенную uniqоперацию в целом?

Lazer
источник

Ответы:

54
perl -ne 'print unless $seen{$_}++' data.txt

Или, если вы должны бесполезно использоватьcat :

cat data.txt | perl -ne 'print unless $seen{$_}++'

Вот awkперевод для систем, в которых отсутствует Perl:

awk '!seen[$0]++' data.txt
cat data.txt | awk '!seen[$0]++'
CJM
источник
3
Немного более короткий сценарий awk{ if (!seen[$0]++) print }
camh
1
@fred, если ваш файл действительно не очень большой, любая версия набирает больше времени, чем запускается.
CJM
8
Версия AWK можно сделать еще короче, оставив вне if, print, скобки и фигурные скобки:awk '!seen[$0]++'
Гордон Дэвиссон
2
@Legate, это имя массива, в котором мы записываем каждую строку, которую видели. Вы можете изменить его '!LarryWall[$0]++'на все заботы, но «увиденное» помогает людям лучше понять программу.
CJM
1
@Sadi, это действительно нужно было задавать как вопрос, а не как комментарий. Но некоторые строки в этом файле заканчиваются пробелом, а некоторые - нет. Эти команды считают всю строку значимой, включая пробелы в конце.
CJM
13

У Джона есть инструмент под названием unique:

usr@srv % cat data.txt | unique out
usr@srv % cat out
aaaaaa
cccccc
bbbbbb

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

usr@srv % cat data.txt | nl | sort -k 2 | uniq -f 1 | sort -n | sed 's/\s*[0-9]\+\s\+//'
aaaaaa
cccccc
bbbbbb

nlпечатает номера строк перед строками, поэтому, если мы sort/ uniqза ними, мы можем восстановить первоначальный порядок строк. sedпросто удаляет номера строк после этого;)

binfalse
источник
Есть ли комбинация общих команд Linux, которые могут сделать то же самое?
Lazer
7
Что вы упустили в "без сортировки данных"?
Тотор
@Totor - см menkus " ответ на аналогичное замечание. @binfalse - ваше второе решение не работает (возможно, оно работает с этим тривиальным образцом, но не работает с некоторыми реальными данными). Пожалуйста, исправьте это, например, это должно всегда работать:nl -ba -nrz data.txt | sort -k2 -u | sort | cut -f2
don_crissti
6

Я предпочитаю использовать это:

cat -n data.txt | sort --key=2.1 -b -u | sort -n | cut -c8-

cat -n добавляет номера строк,

sort --key=2.1 -b -u сортирует по второму полю (после добавленных номеров строк), игнорируя начальные пробелы, сохраняя уникальные строки

sort -n сортирует в строгом числовом порядке

cut -c8- сохранить все символы от столбца 8 до EOL (т. е. пропустить добавленные номера строк)

menkus
источник
5
> Как получить только уникальные результаты без сортировки данных? > без сортировки данных
Ян Викхольм,
7
«без сортировки данных» появляется только в заголовке. Фактически необходимо: «отобразить все строки из исходного файла, удалив все дубликаты (не только последовательные), сохранив при этом исходный порядок операторов в файле».
Menkus
1
@menkus ключ "при сохранении исходного порядка операторов в файле". Этот ответ не достигает этого.
Эндрю Ферье
2

В Perl есть модуль, который вы можете использовать и который включает функцию uniq. Поэтому, если вы сохраняете свои данные, загруженные в массив в Perl, вы просто вызываете функцию, подобную этой, чтобы сделать ее уникальной, но при этом сохранить первоначальный порядок.

use List::MoreUtils qw(uniq)    
@output = uniq(@output);

Вы можете прочитать больше об этом модуле здесь: Список :: MoreUtils

SLM
источник
Может ли это обрабатывать огромные файлы, например, 500 ГБ?
Мальчик