¿Eliminar filas duplicadas en vi?

123

Tengo un archivo de texto que contiene una larga lista de entradas (una en cada línea). Algunos de estos son duplicados y me gustaría saber si es posible (y si es así, cómo) eliminar los duplicados. Estoy interesado en hacer esto desde vi / vim, si es posible.

Sydius
fuente
1
Parece un duplicado de stackoverflow.com/questions/746689/…
Nathan Fellman
4
Este tiene 1 año; ese es 10 meses. Entonces, al revés.
Sydius
El consenso de @Sydius ahora es priorizar el recuento de votos a favor (del que también tienes más): meta.stackexchange.com/questions/147643/… Y esos no son duplicados, ese no menciona a Vim :-)
Ciro Santilli 郝海东 冠状 病六四 事件 法轮功

Respuestas:

269

Si está de acuerdo con ordenar su archivo, puede usar:

:sort u
Brian Carper
fuente
6
Esto es tan hermoso. ¡Gracias!
Shrayas
8
Si la clasificación es inaceptable, utilice :%!uniqpara eliminar las entradas duplicadas sin clasificar el archivo.
cryptic0
una vez que usa el comando, todo el archivo cambia? como vuelves Ya
guardé
Simplemente use el comando deshacer de Vim :u
adampasz
25

Prueba esto:

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

Busca cualquier línea seguida inmediatamente por una o más copias de sí mismo y la reemplaza con una sola copia.

Sin embargo, haga una copia de su archivo antes de intentarlo. No está probado.

Sean
fuente
1
@hop Gracias por probarlo por mí. No tenía acceso a vim en ese momento.
Sean
2
esto resalta todas las líneas duplicadas para mí pero no se borran, ¿me estoy perdiendo un paso aquí?
ak85
Estoy bastante seguro de que esto también resaltará una línea seguida de una línea que tiene el mismo "prefijo" pero es más larga.
hippietrail
3
El único problema con esto es que si tiene múltiples duplicados (3 o más de las mismas líneas), debe ejecutar esto muchas veces hasta que desaparezcan todos los dups, ya que esto solo los elimina un conjunto de dups a la vez.
horta
2
Otro inconveniente de esto: esto no funcionará a menos que sus líneas duplicadas ya estén una al lado de la otra. Clasificar primero sería una forma de asegurarse de que estén uno al lado del otro. En ese momento, las otras respuestas probablemente sean mejores.
horta
23

Desde la línea de comando simplemente haz lo siguiente:

sort file | uniq > file.new
Kevin
fuente
1
Esto fue muy útil para mí para un archivo enorme. ¡Gracias!
Rafid
1
No pude conseguir que la respuesta aceptada funcionara, ya que :sort uestaba colgando en mi archivo grande. Esto funcionó muy rápida y perfectamente. ¡Gracias!
Tgsmith61591
1
'uniq' is not recognized as an internal or external command, operable program or batch file.
hippietrail
1
Sí, probé esta técnica en un archivo de 2,3 GB y fue sorprendentemente rápido.
DanM
@hippietrail ¿Estás en una PC con Windows? Quizás puedas usar cygwin.
12431234123412341234123
8

awk '!x[$0]++' yourfile.txtsi desea conservar el orden (es decir, la clasificación no es aceptable). Para invocarlo desde vim, :!se puede utilizar.

Rovin Bhandari
fuente
4
¡Esto es adorable! ¡No necesitar ordenar es exactamente lo que estaba buscando!
Cometsong
6
g/^\(.*\)$\n\1/d

Funciona para mí en Windows. Sin embargo, las líneas deben ordenarse primero.

Bridgey
fuente
1
Esto eliminará una línea que sigue a una línea que es su prefijo: aaaaseguida de aaaabbeliminará por aaaaerror.
hippietrail
5

Combinaría dos de las respuestas anteriores:

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

1G
!Gsort
1G
!Guniq

Si estaba interesado en ver cuántas líneas duplicadas se eliminaron, use control-G antes y después para verificar la cantidad de líneas presentes en su búfer.

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

Seleccione las líneas en modo de línea visual ( Shift+ v), luego :!uniq. Eso solo detectará duplicados que vengan uno tras otro.

derobert
fuente
1
Solo tenga en cuenta que esto solo funcionará en computadoras con el programa uniq instalado, es decir, Linux, Mac, Freebsd, etc.
anteatersa
Esta será la mejor respuesta para aquellos que no necesitan clasificación. Y si es usuario de Windows, considere probar Cygwin o MSYS.
fx-kirin
1

Con respecto a cómo se puede implementar Uniq en VimL, ​​busque Uniq en un complemento que estoy manteniendo . Verá varias formas de implementarlo que se proporcionaron en la lista de correo de Vim.

De lo contrario, :sort ues de hecho el camino a seguir.

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

o

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

Esta es mi respuesta para ti, ¡puede eliminar varias líneas duplicadas y solo mantener una, no eliminar!

cn8341
fuente
0

yo usaría !}uniq , pero eso solo funciona si no hay líneas en blanco.

Para cada línea en un archivo de uso: :1,$!uniq.

Chris Dodd
fuente
0

Esta versión solo elimina las líneas repetidas que están contigo. Quiero decir, solo borra líneas repetidas consecutivas. Usando el mapa dado, la función nota problemas con líneas en blanco. Pero si cambia el REGEX para que coincida con el inicio de la línea ^, también eliminará las líneas en blanco duplicadas.

" 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>
Sergio Araujo
fuente
0

Un método alternativo que no usa vi / vim (para archivos muy grandes) es, desde la línea de comandos de Linux, use sort y uniq:

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

Esto funcionó para mí para ambos .csvy.txt

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

Explicación: La primera parte del comando imprime filas únicas y la segunda parte, es decir, después de la flecha central, es para guardar la salida de la primera parte.

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

>

<newFileName>

Pablo
fuente