Removendo linhas duplicadas no vi?

122

Eu tenho um arquivo de texto que contém uma longa lista de entradas (uma em cada linha). Algumas delas são duplicadas, e eu gostaria de saber se é possível (e se sim, como) remover as duplicatas. Estou interessado em fazer isso no vi / vim, se possível.

Sydius
fonte
1
Parece uma duplicata de stackoverflow.com/questions/746689/…
Nathan Fellman
4
Este tem 1 ano de idade; esse é de 10 meses. Então, o contrário.
Sydius
O consenso do @Sydius agora é priorizar a contagem de votos positivos (dos quais você também tem mais): meta.stackexchange.com/questions/147643/… E esses não são duplicados, que não são mencionados no Vim :-)
Ciro Santilli 郝海东 冠状 病#

Respostas:

268

Se você estiver bem em classificar seu arquivo, poderá usar:

:sort u
Brian Carper
fonte
6
Isto é tao bonito. Obrigado!
Shrayas
8
Se a classificação for inaceitável, use :%!uniqpara simplesmente remover entradas duplicadas sem classificar o arquivo.
cryptic0
Depois de usar o comando, todo o arquivo é alterado? como voce volta Eu já salvei o arquivo por engano ... meu mal
nilon
Basta usar o comando desfazer do Vim :u
adampasz
25

Tente o seguinte:

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

Ele procura por qualquer linha seguida imediatamente por uma ou mais cópias de si mesma e a substitui por uma única cópia.

Faça uma cópia do seu arquivo antes de tentar. Não foi testado.

Sean
fonte
1
@hop Obrigado por testá-lo para mim. Eu não tinha acesso ao vim na época.
217 Sean
2
isso destaca todas as linhas duplicadas para mim, mas não exclui, estou perdendo uma etapa aqui?
precisa saber é
Tenho certeza de que isso também destacará uma linha seguida por uma linha que tem o mesmo "prefixo", mas é mais longa.
Hippietrail
3
O único problema com isso é que, se você tiver várias duplicatas (3 ou mais das mesmas linhas), precisará executá-lo várias vezes até que todos os dups sejam desativados, pois isso os remove apenas um conjunto de dups por vez.
horta
2
Outra desvantagem disso: isso não funcionará, a menos que suas linhas duplicadas já estejam próximas uma da outra. Classificar primeiro seria uma maneira de garantir que eles estejam próximos um do outro. Nesse ponto, as outras respostas provavelmente são melhores.
horta
23

Na linha de comando, faça:

sort file | uniq > file.new
Kevin
fonte
1
Isso foi muito útil para mim para um arquivo enorme. Obrigado!
Rafid
1
Não foi possível obter a resposta aceita, pois :sort uestava pendurada no meu arquivo grande. Isso funcionou muito rápido e perfeitamente. Obrigado!
Tgsmith61591
1
'uniq' is not recognized as an internal or external command, operable program or batch file.
Hippietrail
1
Sim - eu tentei essa técnica em um arquivo de 2,3 GB e foi surpreendentemente rápido.
DanM 6/02
@hippietrail Você está no Windows PC? Talvez você possa usar o cygwin.
12431234123412341234123
8

awk '!x[$0]++' yourfile.txtse você deseja preservar o pedido (ou seja, a classificação não é aceitável). Para invocá-lo do vim, :!pode ser usado.

Rovin Bhandari
fonte
4
Isso é adorável! Não precisar classificar é exatamente o que eu estava procurando!
Cometsong
6
g/^\(.*\)$\n\1/d

Funciona para mim no Windows. Porém, as linhas devem ser classificadas primeiro.

Bridgey
fonte
1
Isso excluirá uma linha após uma linha que é seu prefixo: aaaaseguido por aaaabbexcluirá aaaaerroneamente.
Hippietrail
5

Eu combinaria duas das respostas acima:

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

1G
!Gsort
1G
!Guniq

Se você estava interessado em ver quantas linhas duplicadas foram removidas, use control-G antes e depois para verificar o número de linhas presentes no seu buffer.

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

Selecione as linhas no modo de linha visual ( Shift+ v) e, em seguida :!uniq. Isso só pega duplicatas que vêm uma após a outra.

derobert
fonte
1
Apenas a nota isso só funcionará em computadores com o programa uniq instalado ie Linux, Mac, FreeBSD etc
anteatersa
Esta será a melhor resposta para aqueles que não precisam de classificação. E se você é usuário do Windows, tente usar o Cygwin ou o MSYS.
Fx-kirin
1

Sobre como o Uniq pode ser implementado no VimL, ​​procure o Uniq em um plugin que estou mantendo . Você verá várias maneiras de implementá-lo, fornecidas na lista de discussão do Vim.

Caso contrário, :sort ué realmente o caminho a percorrer.

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

ou

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

esta é a minha resposta para você, ele pode remover várias linhas duplicadas e manter apenas uma que não seja removida!

cn8341
fonte
0

Eu usaria !}uniq, mas isso só funciona se não houver linhas em branco.

Para cada linha em um uso arquivo: :1,$!uniq.

Chris Dodd
fonte
0

Esta versão remove apenas linhas repetidas que são contíguas. Quero dizer, apenas exclui linhas repetidas consecutivas. Usando o mapa fornecido, a função nota bagunçar as linhas em branco. Mas se alterar o REGEX para corresponder ao início da linha, ^ele também removerá as linhas em branco 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>
SergioAraujo
fonte
0

Um método alternativo que não usa o vi / vim (para arquivos muito grandes) é da linha de comando do Linux use sort e uniq:

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

Isso funcionou para mim para ambos .csve.txt

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

Explicação: A primeira parte do comando imprime linhas exclusivas e a segunda parte, ou seja, após a seta do meio é salvar a saída da primeira parte.

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

>

<newFileName>

Paulo
fonte