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.



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

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


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.


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

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.


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.


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.


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.


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.


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!


0

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

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


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>

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

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>

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.