Localizar e excluir linhas repetidas em um arquivo texto

Publicado por Gabriel Fernandes (última atualização em 22/10/2009)

[ Hits: 24.681 ]

Homepage: http://cd2.com.br

Download limpa_duplicados.sh

Download 1255971739.limpa_duplicados.sh (versão 2)




Este script localiza linhas repetidas em determinado arquivo texto e cria um novo arquivo (ARQUIVO-SAIDA) sem as linhas repetidas, um arquivo somente com as linhas que repetem (ARQUIVO-DUPLICADOS) e por último um arquivo com o estatísticas do resultado (ARQUIVO-LOG).

Uso: ./limpa_duplicados.sh /caminho/do/arquivo caracteres início

Parâmetros:
- /caminho/do/arquivo = caminho completo do arquivo;
- caracteres = quantidade de caracteres que compõem a chave da linha (opcional, padrão=450);
- inicio = posição inicial da chave, começando em 0 - ZERO (opcional, padrão=0);

Exemplo: ./limpa_duplicados.sh arquivo.txt 450 0

Precisa de ajuda? Fale comigo!
[email protected]

  



Versões atualizadas deste script

Versão 2 - Enviado por Gabriel em 19/10/2009

Changelog: Mesmo resultado utilizando o programa AWK, obrigado pela sugestão SMarcell.
Fiz uma pequena alteração para ficar mais fácil de entender para quem não tem muito conhecimento do AWK:

SMarcell sugeriu: printf "$(awk '!i[$0]++' arquivo) \n" > arquivo

Alterado para: awk '{ if ( !umArrayLinhas[$0]++ ) { print $0 } }' arquivo > "arquivo"

Valeus!

Download 1255971739.limpa_duplicados.sh


Esconder código-fonte

#!/bin/bash
# limpa_duplicados - Copyright (C) 2009 Gabriel Fernandes <[email protected]>

if [ ! -f "$1" ] ; then
  echo ""
  echo "limpa_duplicados - Copyright (C) 2009 Gabriel Fernandes"
  echo ""
  echo "Use: $0 /caminho/do/arquivo caracteres inicio"
  echo ""
  echo "Parametros:"
  echo "/caminho/do/arquivo = Caminho completo do arquivo;"
  echo "caracteres = Quantidade de caracteres que compoem a chave da linha (opcional, padrao=450);"
  echo "inicio = Posicao inicial da chave, comecando em 0 - ZERO (opcional, padrao=0);"
  echo ""
  echo "Exemplo: $0 arquivo.txt 450 0"
  echo ""
  echo "Precisa de ajuda? Fale comigo!"
  echo "[email protected]"
  echo ""
  exit 1
fi

# Recebe caminho completo do arquivo para processar
ARQUIVO=$1
ARQUIVO_SAIDA="$ARQUIVO-SAIDA"
ARQUIVO_DUPLICADOS="$ARQUIVO-DUPLICADOS"
# Recebe parametros da chave
CARACTERES=$2
INICIO=$3

# apaga arquivo antigos ja processados
rm -rf "$ARQUIVO-SAIDA" "$ARQUIVO-DUPLICADOS"
# faz backup do arquivo original
cp "$ARQUIVO" "$ARQUIVO-ORIGINAL"

# Conta quantidade linha para processar
NUM_LINHAS=$(cat $ARQUIVO | wc -l)
let NUM_LINHAS++

# Inicia contadores
CONT_LINHAS_DUPLICADAS="0"
CONT_LINHAS_SAIDA="0"
CONT_LINHAS_PROCESSADAS="1"

while read LINHA ; do
  # Carrega os primeiros X caracteres da linha, aqui neste ponto voce pode arrumar a precisao do teste
  # aumentando ou diminuindo a quantidade de caracteres a ser testado na linha, o padrão quando omisso eh 450
  if [ ! -f "$2" ] || [ ! -f "$3" ]; then
    LINHA_ATUAL=${LINHA:0:450} 
  else
    LINHA_ATUAL=${LINHA:$INICIO:$CARACTERES} 
  fi

  # Verifica quantas vezes esta linha foi encontrada no arquivo
  QTDE_LINHAS_LOCALIZADAS_ORIGINAL=$(grep "$LINHA_ATUAL" $ARQUIVO | wc -l)

  if [ "$QTDE_LINHAS_LOCALIZADAS_ORIGINAL" == "1" ]; then
    let CONT_LINHAS_SAIDA++
    echo "$LINHA" >> $ARQUIVO_SAIDA

  else
    # Verifica se a linha repetida ja esta no arquivo novo
    QTDE_LINHAS_LOCALIZADAS_NOVO=$(grep "$LINHA_ATUAL" $ARQUIVO_SAIDA | wc -l)
    if [ "$QTDE_LINHAS_LOCALIZADAS_NOVO" == "0" ]; then
      let CONT_LINHAS_DUPLICADAS++
      let CONT_LINHAS_SAIDA++
      echo "$LINHA" >> $ARQUIVO_SAIDA
      echo "$LINHA" >> $ARQUIVO_DUPLICADOS
    fi
  fi

  let CONT_LINHAS_PROCESSADAS++
  clear
  echo "Processando arquivo: $ARQUIVO"
  echo "Registro:$CONT_LINHAS_PROCESSADAS de $NUM_LINHAS"
  echo "Normal:$CONT_LINHAS_SAIDA Duplo:$CONT_LINHAS_DUPLICADAS"

done < $ARQUIVO

  echo "Processado arquivo: $ARQUIVO" > $ARQUIVO-LOG
  echo "Registro:$CONT_LINHAS_PROCESSADAS de $NUM_LINHAS" >> $ARQUIVO-LOG
  echo "Normal:$CONT_LINHAS_SAIDA Duplo:$CONT_LINHAS_DUPLICADAS" >> $ARQUIVO-LOG

Scripts recomendados

script para criar Maildir

Agenda desenvolvida em Shell Script

Backup para CD-R/RW e DVD+/- R/RW

Backup com TAR em LOG usando FITA LTO/DLT com filtro de arquivos

Retra de iptables para DMZ na porta 80


  

Comentários
[1] Comentário enviado por SMarcell em 18/10/2009 - 06:20h

Geralmente eu utilizava o sort para remover linhas duplicadas dum arquivo

sort -o arquivo -u arquivo

O problema era que em alguns casos as linhas não deveriam ser ordenadas! mas o sort (obviamente!) as ordenava... então resolvi utilizar o awk:

printf "$(awk '!i[$0]++' arquivo) \n" > arquivo

E pronto! problema resolvido.

Só complementando o teu post! ;)

[2] Comentário enviado por uberalles em 22/10/2009 - 14:38h

Muito bacana a dica do AWK!

Só uma coisa: pra quem usa Solaris e não tem o GAWK, por exemplo, dá pra fazer com o NAWK:
wc -l .bash_history
2856 .bash_history

nawk '!i[$0]++' .bash_history |wc -l
689

[3] Comentário enviado por SMarcell em 23/10/2009 - 23:22h

Também é possível utilizar a linguagem Perl para fazer isso:

perl -ne '$i{"$_"}++ || print' < input > output

=)

[4] Comentário enviado por vicentedeandrade em 29/10/2009 - 15:00h

Muito bomo script. Me ajudou muito!

[5] Comentário enviado por GilsonDeElt em 18/01/2011 - 13:38h

Muito bom, cara!
Ajudou um bocado aqui!
Valeu! =)

[6] Comentário enviado por nayamonia em 18/01/2011 - 13:45h

Valeu galera.


[7] Comentário enviado por cadu_flp em 25/01/2011 - 18:22h

Muito bom mesmo, resolveu meu problema.
Valeu!!!

[8] Comentário enviado por leonardo_f em 25/01/2011 - 18:25h

Obrigado, simplesmente resolveu o meu problema, muito bom!!!

[9] Comentário enviado por kraucer em 11/03/2011 - 10:35h

Pô amigo, muito legal amigo! Só uma dica: poderia classificar o script como GPL!


Contribuir com comentário