Znajdź zduplikowane linie w pliku i policz, ile razy każda linia została zduplikowana?


529

Załóżmy, że mam plik podobny do następującego:

123 
123 
234 
234 
123 
345

Chciałbym dowiedzieć się, ile razy „123” zostało zduplikowane, ile razy „234” zostało zduplikowane, itd. Idealnie byłoby, gdyby wynik był:

123  3 
234  2 
345  1

4
W jakim języku chcesz używać?
VMAtm

Odpowiedzi:


791

Zakładając, że w jednym wierszu jest jedna liczba:

sort <file> | uniq -c

Możesz użyć bardziej szczegółowej --countflagi również w wersji GNU, np. W systemie Linux:

sort <file> | uniq --count

3
Robię to jednak algorytmicznie, nie wydaje się to być najbardziej wydajnym podejściem (O (n log n) * avg_line_len gdzie n jest liczbą linii). Pracuję na plikach o wielkości kilku gigabajtów, więc kluczową kwestią jest wydajność. Zastanawiam się, czy istnieje narzędzie, które wykonuje tylko zliczanie w jednym przebiegu przy użyciu drzewa prefiksów (w moim przypadku ciągi często mają wspólne prefiksy) lub podobne, które powinny załatwić sprawę w O (n) * avg_line_len. Czy ktoś zna takie narzędzie wiersza polecenia?
Droggl

21
Dodatkowym krokiem jest przekazanie danych wyjściowych do końcowego polecenia „sort -n”. To posortuje wyniki według najczęściej występujących linii.
samoz

79
Jeśli chcesz wydrukować tylko zduplikowane linie, użyj „uniq -d”
DmitrySandalov

6
Jeśli chcesz ponownie posortować wynik, możesz użyć sortponownie w następujący sposób:sort <file> | uniq -c | sort -n
Abhishek Kashyap

413

Spowoduje to wydrukowanie tylko zduplikowanych linii z podaniem:

sort FILE | uniq -cd

lub, z długimi opcjami GNU (w systemie Linux):

sort FILE | uniq --count --repeated

na BSD i OSX musisz użyć grep, aby odfiltrować unikalne linie:

sort FILE | uniq -c | grep -v '^ *1 '

W podanym przykładzie wynik byłby następujący:

  3 123
  2 234

Jeśli chcesz wydrukować liczby dla wszystkich linii, w tym tych, które pojawiają się tylko raz:

sort FILE | uniq -c

lub, z długimi opcjami GNU (w systemie Linux):

sort FILE | uniq --count

Dla danych wejściowych dane wyjściowe to:

  3 123
  2 234
  1 345

Aby posortować dane wyjściowe z najczęstszymi wierszami na górze, możesz wykonać następujące czynności (aby uzyskać wszystkie wyniki):

sort FILE | uniq -c | sort -nr

lub, aby uzyskać tylko zduplikowane linie, najczęściej:

sort FILE | uniq -cd | sort -nr

w OSX i BSD wersja ostateczna staje się:

sort FILE | uniq -c | grep -v '^ *1 ' | sort -nr

1
Dobra uwaga z opcją --repeated lub -d. O wiele bardziej dokładne niż używanie „| grep 2” lub podobnego!
Lauri

Jak zmodyfikować to polecenie, aby pobrać wszystkie wiersze, których liczba powtórzeń przekracza 100?
Black_Rider

@Black_Rider Dodanie | sort -nlub | sort -nrdo potoku posortuje dane wyjściowe według liczby powtórzeń (odpowiednio rosnąco lub malejąco). Nie o to pytasz, ale pomyślałem, że to może pomóc.
Andrea

1
@Black_Rider awk wydaje się być w stanie wykonać wszelkiego rodzaju obliczenia: w twoim przypadku możesz to zrobić| awk '$1>100'
Andrea

4
@fionbio Wygląda na to, że nie można używać -c i -d razem na OSX uniq . Dzięki za wskazanie. Możesz użyć grep, aby odfiltrować unikalne linie :sort FILE | uniq -c | grep -v '^ *1 '
Andrea

72

Aby znaleźć i policzyć zduplikowane linie w wielu plikach, możesz wypróbować następujące polecenie:

sort <files> | uniq -c | sort -nr

lub:

cat <files> | sort | uniq -c | sort -nr

30

Przez :

awk '{dups[$1]++} END{for (num in dups) {print num,dups[num]}}' data

W awk 'dups[$1]++'poleceniu zmienna $1przechowuje całą zawartość kolumny 1, a nawiasy kwadratowe mają dostęp do tablicy. Tak więc, dla każdej pierwszej kolumny linii w datapliku, węzeł nazwanej tablicy dupsjest zwiększany.

Na koniec zapętlamy dupstablicę numjako zmienną i najpierw wypisujemy zapisane liczby, a następnie ich liczbę zduplikowanych wartości dups[num].

Zauważ, że twój plik wejściowy ma spacje na końcu niektórych linii, jeśli je wyczyścisz, możesz użyć $0zamiast $1polecenia in powyżej :)


1
Czy to nie jest przesada, biorąc pod uwagę, że mamy uniq?
Nathan Fellman,

9
sort | uniqa rozwiązanie awk ma całkiem inną kompromis między wydajnością i zasobami: jeśli pliki są duże, a liczba różnych linii jest niewielka, rozwiązanie awk jest znacznie wydajniejsze. Jest liniowy pod względem liczby linii, a wykorzystanie miejsca jest liniowe pod względem liczby różnych linii. OTOH, rozwiązanie awk musi zachować wszystkie różne linie w pamięci, podczas gdy sortowanie (GNU) może uciekać się do plików tymczasowych.
Lars Noschinski

14

W systemie Windows za pomocą „Windows PowerShell” użyłem polecenia wymienionego poniżej, aby to osiągnąć

Get-Content .\file.txt | Group-Object | Select Name, Count

Możemy również użyć polecenia cmdlet where-object do filtrowania wyniku

Get-Content .\file.txt | Group-Object | Where-Object { $_.Count -gt 1 } | Select Name, Count

czy możesz usunąć wszystkie wystąpienia duplikatów oprócz ostatniego ... bez zmiany kolejności sortowania pliku?
jparram

6

Zakładając, że masz dostęp do standardowej powłoki Unix i / lub środowiska cygwin:

tr -s ' ' '\n' < yourfile | sort | uniq -d -c
       ^--space char

Zasadniczo: przekonwertuj wszystkie znaki spacji na podziały wierszy, a następnie posortuj przetłumaczone dane wyjściowe i podaj je do uniq i policz duplikaty linii.

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.