Supprimer les lignes en double dans vi?

123

J'ai un fichier texte qui contient une longue liste d'entrées (une sur chaque ligne). Certains d'entre eux sont des doublons, et j'aimerais savoir s'il est possible (et si oui, comment) de supprimer les doublons. Je suis intéressé à faire cela depuis vi / vim, si possible.

Sydius
la source
1
On dirait un double de stackoverflow.com/questions/746689/…
Nathan Fellman
4
Celui-ci a 1 an; celui-là est de 10 mois. Donc, autrement.
Sydius
Le consensus @Sydius est maintenant de donner la priorité au nombre de votes positifs (dont vous avez aussi plus): meta.stackexchange.com/questions/147643/… Et ce ne sont pas des doublons, que l'on ne mentionne pas Vim :-)
Ciro Santilli 郝海东 冠状 病六四 事件 法轮功

Réponses:

269

Si vous êtes d'accord pour trier votre fichier, vous pouvez utiliser:

:sort u
Brian Carper
la source
6
C'est tellement beau. Merci!
Shrayas
8
Si le tri est inacceptable, utilisez :%!uniqpour supprimer simplement les entrées en double sans trier le fichier.
cryptic0
une fois que vous utilisez la commande, tout le fichier change? comment reviens-tu? J'ai déjà enregistré le fichier par erreur ... mon mauvais
nilon
Utilisez simplement la commande d'annulation de Vim :u
adampasz
25

Essaye ça:

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

Il recherche toute ligne immédiatement suivie d'une ou plusieurs copies de lui-même et la remplace par une seule copie.

Faites une copie de votre fichier avant de l'essayer. Ce n'est pas testé.

Sean
la source
1
@hop Merci de l'avoir testé pour moi. Je n'avais pas accès à vim à l'époque.
Sean
2
cela met en évidence toutes les lignes en double pour moi mais ne supprime pas, est-ce que je manque une étape ici?
ak85 le
Je suis sûr que cela mettra également en évidence une ligne suivie d'une ligne qui a le même "préfixe" mais qui est plus longue.
hippietrail
3
Le seul problème avec ceci est que si vous avez plusieurs doublons (3 ou plus des mêmes lignes), vous devez l'exécuter plusieurs fois jusqu'à ce que toutes les dups aient disparu, car cela ne les supprime qu'un ensemble de dups à la fois.
horta
2
Autre inconvénient: cela ne fonctionnera que si vos lignes dupliquées sont déjà côte à côte. Le tri en premier serait une façon de s'assurer qu'ils sont côte à côte. À ce stade, les autres réponses sont probablement meilleures.
horta
23

À partir de la ligne de commande, faites simplement:

sort file | uniq > file.new
Kevin
la source
1
C'était très pratique pour moi pour un gros fichier. Merci!
Rafid
1
Impossible de faire fonctionner la réponse acceptée, car elle :sort uétait accrochée à mon gros fichier. Cela a fonctionné très rapidement et parfaitement. Je vous remercie!
Tgsmith61591
1
'uniq' is not recognized as an internal or external command, operable program or batch file.
hippietrail
1
Oui, j'ai essayé cette technique sur un fichier de 2,3 Go, et c'était incroyablement rapide.
DanM
@hippietrail Vous êtes sur un PC Windows? Peut-être que vous pouvez utiliser cygwin.
12431234123412341234123
8

awk '!x[$0]++' yourfile.txtsi vous souhaitez conserver l'ordre (c'est-à-dire que le tri n'est pas acceptable). Afin de l'invoquer depuis vim, :!peut être utilisé.

Rovin Bhandari
la source
4
C'est adorable! Ne pas avoir besoin de trier, c'est exactement ce que je recherchais!
Cometsong
6
g/^\(.*\)$\n\1/d

Fonctionne pour moi sur Windows. Les lignes doivent cependant être triées en premier.

Bridgey
la source
1
Cela supprimera une ligne après une ligne qui est son préfixe: aaaasuivi de aaaabbsupprimera par aaaaerreur.
hippietrail
5

Je combinerais deux des réponses ci-dessus:

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

1G
!Gsort
1G
!Guniq

Si vous souhaitez voir combien de lignes dupliquées ont été supprimées, utilisez control-G avant et après pour vérifier le nombre de lignes présentes dans votre tampon.

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

Sélectionnez les lignes en mode visuel-ligne ( Shift+ v), puis :!uniq. Cela n'attrapera que les doublons qui se succèdent.

derobert
la source
1
Juste pour noter que cela ne fonctionnera que sur les ordinateurs avec le programme uniq installé, c'est-à-dire Linux, Mac, Freebsd, etc.
anteatersa
Ce sera la meilleure réponse à ceux qui n'ont pas besoin de tri. Et si vous êtes utilisateur de Windows, pensez à essayer Cygwin ou MSYS.
fx-kirin
1

En ce qui concerne la façon dont Uniq peut être implémenté dans VimL, ​​recherchez Uniq dans un plugin que je gère . Vous verrez différentes façons de l'implémenter qui ont été données sur la liste de diffusion Vim.

Sinon, :sort uc'est bien la voie à suivre.

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

ou

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

c'est ma réponse pour vous, il peut supprimer plusieurs lignes en double et n'en garder qu'une seule pas supprimer!

cn8341
la source
0

J'utiliserais !}uniq, mais cela ne fonctionne que s'il n'y a pas de lignes vides.

Pour chaque ligne dans une utilisation du fichier: :1,$!uniq.

Chris Dodd
la source
0

Cette version supprime uniquement les lignes répétées qui sont contigues. Je veux dire, ne supprime que les lignes répétées consécutives. En utilisant la carte donnée, la fonction note des erreurs avec des lignes vides. Mais si vous modifiez le REGEX pour qu'il corresponde au début de la ligne, ^il supprimera également les lignes vierges dupliquées.

" 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
la source
0

Une méthode alternative qui n'utilise pas vi / vim (pour les fichiers très volumineux), est à partir de la ligne de commande Linux, utilisez sort et uniq:

sort {file-name} | uniq -u
william-1066
la source
0

Cela a fonctionné pour moi à la fois .csvet.txt

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

Explication: La première partie de la commande imprime des lignes uniques et la deuxième partie, c'est-à-dire après la flèche du milieu, consiste à enregistrer la sortie de la première partie.

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

>

<newFileName>

Paul
la source