Jak uzyskać tylko unikalne wyniki bez konieczności sortowania danych?


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
$

W rezultacie potrzebuję wyświetlić wszystkie wiersze z oryginalnego pliku, usuwając wszystkie duplikaty (nie tylko kolejne), zachowując oryginalną kolejność instrukcji w pliku .

Tutaj, w tym przykładzie, rzeczywiście szukałem wyniku

aaaaaa
cccccc
bbbbbb

Jak mogę ogólnie przeprowadzić tę uogólnioną uniqoperację?

Odpowiedzi:


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

Lub, jeśli musisz mieć bezużyteczne użyciecat :

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

Oto awktłumaczenie dla systemów pozbawionych Perla:

awk '!seen[$0]++' data.txt
cat data.txt | awk '!seen[$0]++'

3
Nieco krótszy skrypt awk to{ if (!seen[$0]++) print }
camh

1
@fred, chyba że twój plik jest naprawdę ogromny, każda z wersji potrzebuje więcej czasu niż na uruchomienie.
cjm

8
Wersja awk może być jeszcze krótszy, pozostawiając na zewnątrz if, printnawiasy i szelki:awk '!seen[$0]++'
Gordon Davisson

2
@ Legate, to nazwa tablicy, w której rejestrujemy każdą linię, którą widzieliśmy. Możesz zmienić to '!LarryWall[$0]++'na wszystkie awk, ale „widziane” pomaga ludziom lepiej zrozumieć program.
cjm

1
@Sadi, to naprawdę powinno być zadawane jako pytanie, a nie komentarz. Ale niektóre wiersze w tym pliku kończą się spacją, a niektóre nie. Te polecenia uznają całą linię za znaczącą, w tym spacje na końcu.
cjm

13

john ma narzędzie o nazwie unique:

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

Osiągnięcie tego samego bez dodatkowych narzędzi w jednym wierszu poleceń jest nieco bardziej złożone:

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

nlwypisuje numery linii przed liniami, więc jeśli my sort/ uniqza nimi możemy przywrócić pierwotną kolejność linii. sedpo prostu usuwa numery linii;)


czy jest jakaś kombinacja typowych poleceń linux, które mogłyby zrobić to samo?
Lazer

7
Czego brakowało w „bez konieczności sortowania danych”?
Totor

@Totor - patrz menkus ' odpowiedź na podobnym komentarzem. @binfalse - twoje drugie rozwiązanie nie działa (być może działa z tą trywialną próbką, ale nie działa z niektórymi danymi wejściowymi z życia). Proszę to naprawić, np. Powinno to zawsze działać:nl -ba -nrz data.txt | sort -k2 -u | sort | cut -f2
don_crissti,

6

Wolę użyć tego:

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

cat -n dodaje numery linii,

sort --key=2.1 -b -u sortuje według drugiego pola (po dodanych numerach linii), ignorując wiodące spacje, zachowując unikalne linie

sort -n sortuje w ścisłej kolejności numerycznej

cut -c8- zachowaj wszystkie znaki od kolumny 8 do EOL (tzn. pomiń dołączone przez nas numery wierszy)


5
> Jak uzyskać tylko unikalne wyniki bez konieczności sortowania danych? > bez konieczności sortowania danych
Jan Wikholm

7
„bez konieczności sortowania danych” pojawia się tylko w tytule. Rzeczywista potrzeba to: „wyświetlić wszystkie wiersze z oryginalnego pliku usuwając wszystkie duplikaty (nie tylko kolejne), zachowując pierwotną kolejność instrukcji w pliku”.
menkus

1
@menkus kluczem jest „przy zachowaniu oryginalnej kolejności instrukcji w pliku”. Ta odpowiedź tego nie osiąga.
Andrew Ferrier,

2

Perl ma moduł, którego można użyć, który zawiera funkcję o nazwie uniq. Jeśli więc dane są ładowane do tablicy w Perlu, wystarczy wywołać taką funkcję, aby była wyjątkowa, ale nadal zachowała pierwotną kolejność.

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

Możesz przeczytać więcej o tym module tutaj: List :: MoreUtils


Czy poradzi sobie z dużymi plikami, np. 500 GB?
Chłopiec,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.