Doppelte Zeilen in vi entfernen?

122

Ich habe eine Textdatei, die eine lange Liste von Einträgen enthält (einen in jeder Zeile). Einige davon sind Duplikate, und ich würde gerne wissen, ob es möglich ist (und wenn ja, wie), Duplikate zu entfernen. Ich bin daran interessiert, dies möglichst innerhalb von vi / vim zu tun.

Sydius
quelle
1
Sieht aus wie ein Duplikat von stackoverflow.com/questions/746689/…
Nathan Fellman
4
Dieser ist 1 Jahr alt; das ist 10 Monate. Also anders herum.
Sydius
@Sydius Konsens besteht nun darin, die Anzahl der Upvotes zu priorisieren (von denen Sie auch mehr haben): meta.stackexchange.com/questions/147643/… Und das sind keine Duplikate, die man nicht erwähnt Vim :-)
Ciro Santilli 郝海东 冠状 病

Antworten:

266

Wenn Sie mit dem Sortieren Ihrer Datei einverstanden sind, können Sie Folgendes verwenden:

:sort u
Brian Carper
quelle
5
Das ist so schön. Vielen Dank!
Shrayas
7
Wenn das Sortieren nicht akzeptabel ist, :%!uniqentfernen Sie einfach doppelte Einträge, ohne die Datei zu sortieren.
cryptic0
Sobald Sie den Befehl verwenden, ändert sich die gesamte Datei? Wie gehst du zurück? Ich habe die Datei bereits versehentlich gespeichert ... mein Bad
Nilon
Verwenden Sie einfach u
Vims
25

Versuche dies:

:%s/^\(.*\)\(\n\1\)\+$/\1/

Es sucht nach einer Zeile, unmittelbar gefolgt von einer oder mehreren Kopien von sich selbst, und ersetzt sie durch eine einzelne Kopie.

Erstellen Sie jedoch eine Kopie Ihrer Datei, bevor Sie sie ausprobieren. Es ist ungetestet.

Sean
quelle
1
@hop Danke, dass du es für mich getestet hast. Ich hatte damals keinen Zugang zu vim.
Sean
2
Dadurch werden alle doppelten Zeilen für mich hervorgehoben, aber nicht gelöscht. Fehlt mir hier ein Schritt?
Ak85
Ich bin mir ziemlich sicher, dass dadurch auch eine Zeile hervorgehoben wird, gefolgt von einer Zeile mit demselben "Präfix", die jedoch länger ist.
Hippietrail
3
Das einzige Problem dabei ist, dass Sie, wenn Sie mehrere Duplikate haben (3 oder mehr derselben Zeilen), dies viele Male ausführen müssen, bis alle Dups verschwunden sind, da dadurch jeweils nur ein Satz Dups entfernt wird.
Horta
2
Ein weiterer Nachteil: Dies funktioniert nur, wenn Ihre doppelten Zeilen bereits nebeneinander liegen. Das erste Sortieren wäre eine Möglichkeit, um sicherzustellen, dass sie nebeneinander liegen. An diesem Punkt sind die anderen Antworten wahrscheinlich besser.
Horta
23

Führen Sie über die Befehlszeile einfach Folgendes aus:

sort file | uniq > file.new
Kevin
quelle
1
Dies war sehr praktisch für mich für eine riesige Datei. Vielen Dank!
Rafid
1
Die akzeptierte Antwort konnte nicht funktionieren, da :sort usie an meiner großen Datei hing. Das hat sehr schnell und perfekt funktioniert. Danke dir!
Tgsmith61591
1
'uniq' is not recognized as an internal or external command, operable program or batch file.
Hippietrail
1
Ja, ich habe diese Technik an einer 2,3-GB-Datei ausprobiert und sie war schockierend schnell.
DanM
@hippietrail Du bist auf Windows PC? Vielleicht können Sie Cygwin verwenden.
12431234123412341234123
8

awk '!x[$0]++' yourfile.txtWenn Sie die Reihenfolge beibehalten möchten (dh das Sortieren ist nicht akzeptabel). Um es von vim aus aufzurufen, :!kann verwendet werden.

Rovin Bhandari
quelle
4
Das ist schön! Nicht sortieren zu müssen ist genau das , wonach ich gesucht habe!
Cometsong
6
g/^\(.*\)$\n\1/d

Funktioniert für mich unter Windows. Zeilen müssen jedoch zuerst sortiert werden.

Bridgey
quelle
1
Dadurch wird eine Zeile nach einer Zeile gelöscht, die das Präfix ist: aaaagefolgt von aaaabbwird aaaafälschlicherweise gelöscht .
Hippietrail
5

Ich würde zwei der obigen Antworten kombinieren:

go to head of file
sort the whole file
remove duplicate entries with uniq

1G
!Gsort
1G
!Guniq

Wenn Sie sehen möchten, wie viele doppelte Zeilen entfernt wurden, verwenden Sie vorher und nachher Strg-G, um die Anzahl der in Ihrem Puffer vorhandenen Zeilen zu überprüfen.

Jon DellOro
quelle
1
'uniq' is not recognized as an internal or external command, operable program or batch file.
Hippietrail
3

Wählen Sie dann die Linien im visuellen Linienmodus ( Shift+ v) aus :!uniq. Das fängt nur Duplikate auf, die nacheinander kommen.

derobert
quelle
1
Nur um zu beachten, dass dies nur auf Computern funktioniert, auf denen das Uniq-Programm installiert ist, z. B. Linux, Mac, Freebsd usw.
Anteatersa
Dies ist die beste Antwort für diejenigen, die keine Sortierung benötigen. Wenn Sie Windows verwenden, sollten Sie Cygwin oder MSYS ausprobieren.
FX-Kirin
1

Suchen Sie in einem von mir verwalteten Plugin nach Uniq, um herauszufinden, wie Uniq in VimL implementiert werden kann . Sie werden verschiedene Möglichkeiten zur Implementierung sehen, die auf der Vim-Mailingliste angegeben wurden.

Ansonsten :sort uist in der Tat der Weg zu gehen.

Luc Hermitte
quelle
0
:%s/^\(.*\)\(\n\1\)\+$/\1/gec

oder

:%s/^\(.*\)\(\n\1\)\+$/\1/ge

Dies ist meine Antwort für Sie, es kann mehrere doppelte Zeilen entfernen und nur eine behalten, nicht entfernen!

cn8341
quelle
0

Ich würde verwenden !}uniq, aber das funktioniert nur, wenn es keine Leerzeilen gibt.

Verwenden Sie für jede Zeile in einer Datei : :1,$!uniq.

Chris Dodd
quelle
0

Diese Version entfernt nur wiederholte Zeilen, die zusammenhängend sind. Ich meine, löscht nur aufeinanderfolgende wiederholte Zeilen. Bei Verwendung der angegebenen Karte stellt die Funktion fest, dass Leerzeilen durcheinander geraten. Wenn Sie den REGEX jedoch so ändern, dass er mit dem Zeilenanfang übereinstimmt ^, werden auch doppelte Leerzeilen entfernt.

" function to delete duplicate lines
function! DelDuplicatedLines()
    while getline(".") == getline(line(".") - 1)
        exec 'norm! ddk'
    endwhile
    while getline(".") == getline(line(".") + 1)
        exec 'norm! dd'
    endwhile
endfunction
nnoremap <Leader>d :g/./call DelDuplicatedLines()<CR>
SergioAraujo
quelle
0

Eine alternative Methode, die vi / vim nicht verwendet (für sehr große Dateien), ist die Verwendung von sort und uniq in der Linux-Befehlszeile:

sort {file-name} | uniq -u
William-1066
quelle
0

Dieser arbeitete für mich für beide .csvund.txt

awk '!seen[$0]++' <filename> > <newFileName>

Erläuterung: Der erste Teil des Befehls druckt eindeutige Zeilen und der zweite Teil, dh nach dem mittleren Pfeil, dient zum Speichern der Ausgabe des ersten Teils.

awk '!seen[$0]++' <filename>

>

<newFileName>

paul
quelle