2009-06-04 15 views
17

Mam zwykły plik tekstowy ze słowami, które są oddzielone przecinkami, na przykład:Jak usunąć duplikaty słów z pliku tekstowego za pomocą polecenia linux

word1, word2, word3, word2, word4, word5, word 3, word6, word7, word3 

chcę usunąć duplikaty i stać :

word1, word2, word3, word4, word5, word6, word7 

Jakieś pomysły? Myślę, że egrep może mi pomóc, ale nie jestem pewien, jak z niego korzystać ...

+1

Czy chcesz, aby słowa były unikatowe w linii lub w całym pliku? Czy chcesz zachować oryginalną kolejność słów, czy też jesteś szczęśliwy, jeśli zamówienie zostanie zmienione? – Beano

+0

Potrzebuję słów uniq w całym pliku. kolejność słów nie jest ważna. – cupakob

+0

Zobacz też: [Jak znaleźć powtarzające się słowa w pliku używając grep/egrep?] (Http://stackoverflow.com/q/33396629/562769) –

Odpowiedz

28

Zakładając, że słowa są po jednej w wierszu, a plik jest już posortowana:

uniq filename 

Jeśli plik nie jest klasyfikowane:

sort filename | uniq 

Jeśli nie jesteś jednym w każdym wierszu i nie masz nic przeciwko temu, że jest jeden w linii:

tr -s [:space:] \\n < filename | sort | uniq 

To nie usuwa interpunkcji, więc może chcesz :

tr -s [:space:][:punct:] \\n < filename | sort | uniq 

Ale to usuwa łącznik z dzielonych wyrazów. "man tr", aby uzyskać więcej opcji.

+0

, który działa dla mnie :) dziękuję bardzo ... muszę tylko umieścić wszystkie słowa z powrotem w jednym wierszu z: cat testfile_out.txt | tr "\ n" ""> testfile_out2.txt – cupakob

+10

"sort -u" usunie potrzebę uniq – Beano

1

Myślę, że będziesz chciał zastąpić spacje znakami nowej linii, użyj polecenia uniq, aby znaleźć unikatowe linie, a następnie ponownie zamień znaki nowej linii spacjami.

+0

uniq tylko porównywać sąsiednie linie, więc to nie zadziała. – Beano

+0

to w połączeniu z sortowaniem – Jonik

3

ruby -pi.bak -e '$_.split(",").uniq.join(",")' filename?

Przyznam, że te dwa rodzaje cytatów są brzydkie.

+2

Ruby nie jest poleceniem Linux! Zakładam, że według polecenia Linuksa oznacza regularne programy GNU. – Danny

+0

@Danny, widziałem to, i możesz to zrobić z nadgorliwą alchemią sed/awk, ale naprawdę myślę, że to jest praca dla języka skryptowego. –

+0

+1, ponieważ wydaje się niezaprzeczalnie elegancka i bardziej przystępna dla śmiertelników w porównaniu do jednej linijki Perla Isora Krivokona :) – Jonik

1

Podejrzewałem, że chcesz, aby słowa były unikalne w jednym wierszu, a nie w całym pliku. Jeśli tak jest, to poniższy skrypt Perla wystarczy.

while (<DATA>) 
{ 
    chomp; 
    my %seen =(); 
    my @words = split(m!,\s*!); 
    @words = grep { $seen{$_} ? 0 : ($seen{$_} = 1) } @words; 
    print join(", ", @words), "\n"; 
} 

__DATA__ 
word1, word2, word3, word2, word4, word5, word3, word6, word7, word3 

Jeśli chcesz niepowtarzalność w całym pliku, można po prostu przenieść %seen hash poza pętlą while(){}.

+2

Perl nie jest poleceniem dla systemu Linux! Zakładam, że według polecenia Linuksa oznacza regularne programy GNU. Z drugiej strony Perl jest zainstalowany wszędzie ... heh. – Danny

+0

Czy możesz wskazać, jaka jest twoja definicja "polecenia Linuksa" (a raczej @brbrighta, tak jak go znasz)? Może polecenie znalezione w dystrybucjach Linuksa? – Beano

+0

Mam na myśli polecenie, które jest zintegrowane z domyślną instalacją najpopularniejszych dystrybucji ... na przykład przypomina grep. – cupakob

2

tworząc niepowtarzalny lista jest bardzo łatwe dzięki uniq, chociaż większość Unix polecenia jak jednej pozycji na wiersz zamiast listy oddzielonych przecinkami, więc musimy zacząć poprzez przekształcenie go do:

$ sed 's/, /\n/g' filename | sort | uniq 
word1 
word2 
word3 
word4 
word5 
word6 
word7 

Najtrudniejszą częścią jest umieszczenie tego w jednym wierszu ponownie z przecinkami jako separatorami, a nie terminatorami. Użyłem do tego jednego perlera, ale jeśli ktoś ma coś bardziej idiomatycznego, edytuj mnie. :)

$ sed 's/, /\n/g' filename | sort | uniq | perl -e '@a = <>; chomp @a; print((join ", ", @a), "\n")' 
word1, word2, word3, word4, word5, word6, word7 
+0

tr "" "\ n" może być bardziej efektywne niż sed w tym przypadku – florin

+0

i działa również – cupakob

+0

Umieszczenie tego w jednej linii jest całkiem proste: sed 's /,/\ n/g' nazwa pliku | sortuj wklej -s -d, | sed 's /, /,/g' Polecenie to wklej, bardzo ładne! – Mapio

0

I nie zapomnij o opcji -c dla użyteczności uniq jeśli jesteś zainteresowany w uzyskaniu liczby słów, jak również.

2

Oto skrypt awk że pozostawi każdą linię w takt, tylko usuwając zduplikowane słowa:

BEGIN { 
    FS=", " 
} 
{ 
    for (i=1; i <= NF; i++) 
     used[$i] = 1 
    for (x in used) 
     printf "%s, ",x 
    printf "\n" 
    split("", used) 
} 
+0

który działa również, ale nie jest doskonały;) wynik zawiera słowo z dwoma przecinkami .... to nie jest duży problem :) dziękuję bardzo – cupakob

1

Natknąłem tego wątku, starając się rozwiązać podobny problem.Łączę kilka plików zawierających hasła, więc naturalnie było dużo dublerów. Ponadto wiele niestandardowych znaków. Tak naprawdę nie potrzebowałem ich posortować, ale wydawało się, że będzie to konieczne do uniq.

Próbowałem:

sort /Users/me/Documents/file.txt | uniq -u 
sort: string comparison failed: Illegal byte sequence 
sort: Set LC_ALL='C' to work around the problem. 
sort: The strings compared were `t\203tonnement' and `t\203tonner' 

Tried:

sort -u /Users/me/Documents/file.txt >> /Users/me/Documents/file2.txt 
sort: string comparison failed: Illegal byte sequence 
sort: Set LC_ALL='C' to work around the problem. 
sort: The strings compared were `t\203tonnement' and `t\203tonner'. 

I nawet próbował przepuszczenie go przez kota pierwszy, po prostu, więc mogłem zobaczyć, czy byliśmy coraz właściwego wejścia.

cat /Users/me/Documents/file.txt | sort | uniq -u > /Users/me/Documents/file2.txt 
sort: string comparison failed: Illegal byte sequence 
sort: Set LC_ALL='C' to work around the problem. 
sort: The strings compared were `zon\351s' and `zoologie'. 

Nie jestem pewien, co się dzieje. Łańcuchy "t \ 203tonnement" i "t \ 203tonner" nie zostały znalezione w pliku, chociaż występują "t/203" i "tonacja", ale na osobnych, niesąsiadujących liniach. To samo z "zon \ 351s".

Co ostatecznie pracował dla mnie było:

awk '!x[$0]++' /Users/me/Documents/file.txt > /Users/me/Documents/file2.txt 

również zachowane słowa, których jedyną różnicą było to sprawa, która jest, co chciałem. Nie potrzebowałem listy posortowanej, więc było dobrze, że tak nie było.

1

Miałem ten sam problem dzisiaj .. listę słów z 238 000 słów, ale około 40 000 z nich było duplikatami. Ja już miałem je w poszczególnych liniach wykonując

cat filename | tr " " "\n" | sort 

usunąć duplikaty po prostu zrobił

cat filename | uniq > newfilename . 

Pracował idealnie błędów i teraz mój plik jest w dół od 1.45MB do 1.01MB

0

otwórz plik za pomocą vim (vim filename) i uruchom polecenie sort z unikalną flagą (:sort u).