2009-06-04 11 views
17

Ho un normale file di testo con le parole, che sono separati da una virgola, ad esempio:Come rimuovere le parole duplicate da un file di testo usando il comando linux

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

voglio eliminare i duplicati e di diventare :

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

Qualsiasi idea? Credo che, egrep mi può aiutare, ma non sono sicuro, come si usa esattamente ....

+1

Vuoi che le parole siano univoche in base alla riga o su tutto il file? Vuoi mantenere l'ordine originale delle parole o sei felice se l'ordine è cambiato? – Beano

+0

ho bisogno delle parole uniq nell'intero file. l'ordine delle parole non è importante. – cupakob

+0

Vedere anche: [Come trovare le parole ripetute in un file utilizzando grep/egrep?] (Http://stackoverflow.com/q/33396629/562769) –

risposta

28

Assumendo che le parole sono uno per riga, e il file è già ordinato:

uniq filename 

Se il file non è ordinato:

sort filename | uniq 

Se non sono uno per riga, e non ti spiace essere uno per riga:

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

Ciò non rimuove la punteggiatura, però, quindi forse vuoi :

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

Ma questo rimuove il trattino dalle parole con trattino. "man tr" per più opzioni.

+0

che funziona per me :) grazie mille ... ho solo bisogno di mettere tutte le parole di nuovo in una riga con: cat testfile_out.txt | tr "\ n" ""> testfile_out2.txt – cupakob

+10

"sort -u" rimuoverebbe la necessità di uniq – Beano

1

penserei si desidera sostituire gli spazi con a capo, utilizzare il comando uniq per trovare unica linee, quindi sostituire nuovamente le nuove righe con gli spazi.

+0

uniq confronta solo le righe adiacenti, quindi non funzionerà. – Beano

+0

lo farà quando combinato con ordinamento – Jonik

3

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

Ammetto che i due tipi di quotazioni sono brutti.

+2

Ruby non è un comando di Linux! Presumo per comando di Linux che intenda normali programmi GNU. – Danny

+0

@Danny, l'ho visto, e potresti farlo con qualche alchimia sed/awk troppo zelante, ma in realtà penso che questo sia un lavoro per un linguaggio di scripting. –

+0

+1 perché questo sembra innegabilmente elegante e più accessibile per i mortali rispetto a quello di Perl di Igor Krivokon :) – Jonik

1

Supponevo che voleste che le parole fossero univoche su una singola riga, piuttosto che su tutto il file. Se questo è il caso, allora lo script Perl qui sotto farà il trucco.

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 

Se si desidera che l'unicità su tutto il file, si può semplicemente spostare il %seen hash fuori del ciclo while(){}.

+2

Perl non è un comando di Linux! Presumo per comando di Linux che intenda normali programmi GNU. Poi di nuovo Perl è installato ovunque ... eh. – Danny

+0

Puoi per favore indicare quale è la tua definizione di "comando Linux" (o meglio di @ rbright come sembri conoscerlo)? Forse un comando trovato nelle distribuzioni Linux? – Beano

+0

intendo un comando, che è integrato nell'installazione predefinita delle distribuzioni più popolari ... ad esempio, qualcosa come grep. – cupakob

2

Creazione di una lista unica è abbastanza facile grazie a uniq, sebbene la maggior parte dei comandi UNIX come una voce per riga, invece di un elenco separato da virgole, quindi dobbiamo cominciare convertendolo in che:

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

La parte più difficile è mettere di nuovo questa riga su una riga con virgole come separatori e non terminatori. Ho usato un perl one-liner per farlo, ma se qualcuno ha qualcosa di più idiomatico, per favore modificami. :)

$ 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" potrebbe essere più efficiente di sed in questo caso – florin

+0

e funziona anche – cupakob

+0

Mettere che su una riga è abbastanza semplice: nome /,/\ n/g nome file | ordinare | incolla -s -d, | sed 's /, /,/g' il comando si incolla, molto bello! – Mapio

0

E non dimenticare l'opzione -c per l'utilità uniq se siete interessati a ottenere un conteggio delle parole pure.

2

Ecco uno script awk che lascerà ogni riga nel tatto, eliminando solo le parole duplicate:

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

che funziona anche, ma non perfetto;) l'output contiene una parola con due virgole .... che non è un grosso problema :) grazie mille – cupakob

1

sono imbattuto in questa discussione durante il tentativo di risolvere più o meno lo stesso problema.Avevo concatenato diversi file contenenti password, quindi naturalmente c'erano molti doppi. Inoltre, molti personaggi non standard. Non avevo davvero bisogno che fossero ordinati, ma sembrava che fosse necessario per uniq.

ho provato:

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' 

provato:

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'. 

E anche provato passando attraverso gatto prima, solo così ho potuto vedere se stavamo ottenendo un ingresso adeguato.

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'. 

Non sono sicuro di cosa stia succedendo. Le stringhe "t \ 203tonnement" e "t \ 203tonner" non si trovano nel file, sebbene vengano trovate "t/203" e "tonnement", ma su linee separate, non adiacenti. Lo stesso con "zon \ 351s".

Ciò che alla fine ha funzionato per me era:

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

It parole anche conservate la cui differenza era solo caso, che è quello che volevo. Non avevo bisogno di ordinare la lista, quindi andava bene che non fosse così.

1

ho avuto lo stesso problema oggi .. un elenco di parole con 238.000 parole ma circa 40.000 di quelle erano duplicati. Ho già li avevo in singole linee facendo

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

per rimuovere i duplicati ho semplicemente fatto

cat filename | uniq > newfilename . 

funzionato perfettamente senza errori e ora il mio file è giù da 1.45MB a 1.01MB

0

aprire il file con vim (vim filename) ed eseguire il comando sort con un flag univoco (:sort u).

Problemi correlati