quinta-feira, 31 de agosto de 2023

Como identificar linhas repetidas num CSV

Uma carga de arquivo CSV estava com problema, então resolvi usar um pouco de Perl para resolver o problema. O Perl adapta-se muito bem ao uso na linha de comando em conjunto com outros programas do Linux.

A minha missão era descobrir linhas duplicadas num arquivo específico. As 6 primeiras colunas constituem a chave primária, então bastaria encontrar os valores repetidos sem olhar as demais colunas.

Vamos começar pelo comando completo e depois vamos analisá-lo por partes.


perl -F';' -pae '$_="\n".join(" ",@F[0..5])' dados.csv \
  | sort \
  | uniq -c \
  | grep -Pv "^\s+1\s"
  

O perl está sendo invocado com os seguintes parâmetros:

  • -F - indica o separador usado no arquivo (neste caso, ';' com aspas simples para evitar problemas com o shell);
  • -p - imprime a linha corrente após o processamento (a atribuição a $_ sobrescreve o valor lido do arquivo) e insere o código num loop;
  • -a - realiza a separação das colunas conforme o parâmetro -F (os valores são inseridos no array @F);
  • -e - indica o código a ser executado.
Então, para cada linha, o perl coloca as colunas dentro do array @F e o nosso código pega apenas as 6 primeiras (nossa chave primária), junta tudo com espaços, e atribui à variável $_, a qual o perl usa para imprimir no terminal.


...
2023 7 GHR       23000352221 0006 23003679769
2023 7 POR       23000355314 0009 00000000000
2023 7 POR       23000353643 0006 00000000000
2023 7 GHR       23000353068 0006 23003652420
2023 7 POR       23000355700 0006 23003594050
2023 7 POR       23000353068 0006 23003652420
2023 7 POR       23000354235 0006 23003621737
...

As linhas "sort" e "uniq -c" ordenam as linhas lexicograficamente e eliminam as linhas duplicadas, adicionando o número de repetições ao início:


...
      2 2023 7 ABZ       23000727144 0005 23003652413 
      1 2023 7 ABZ       23000750717 0003 23004055962 
      1 2023 7 ABZ       23000750886 0003 23003519192 
      1 2023 7 ABZ       23000750886 0003 23003519194 
      1 2023 7 ABZ       23000750886 0004 23003519197 
      1 2023 7 ABZ       23000750886 0004 23003519199 
...

O último grep elimina todas as linhas que não começam com 1 (-v é a negação da expressão e -P indica que está sendo usada uma expressão regular do Perl):


...
      2 2023 7 ABZ       22004359695 0005 23003652423
      2 2023 7 ABZ       22005716393 0002 23003652508
      2 2023 7 ABZ       23000320848 0006 23003652464
      2 2023 7 ABZ       23000727144 0005 23003652413
      2 2023 7 ABZ       23001447112 0004 23003652502
...