Localizar e excluir linhas repetidas em um arquivo texto

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

[ Hits: 28.698 ]

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!
gabriel@duel.com.br

  



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 <gabriel@duel.com.br>

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 "gabriel@duel.com.br"
  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

Salvaguardando configurações.

Script para correção de arquivos Makefile usando comando patch

linkswitch (redundância de internet)

procurar palavras dentro de todos os ficheiros de sub directorias

script de clamav anti-virus


  

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




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts