Localizar e substituir duplicados

1

Eu tenho um arquivo com e-mails concatenados que se parece com o seguinte:

id  emails
1   [email protected]
2   [email protected]
3   [email protected],[email protected],[email protected]

Cada linha tem apenas e-mails distintos, mas pode haver duplicatas de uma linha para outra, como visto acima na linha 1 e na linha 3. Eu preciso remover duplicatas do arquivo para que o arquivo se pareça com o seguinte:

id  emails
1   [email protected]
2   [email protected]
3   [email protected],[email protected]

Isso significa que preciso verificar cada linha em relação a todas as linhas subsequentes. Isso não é viável para fazer com qualquer tipo de script iterativo, dada a quantidade de dados que tenho. Eu sinto que há uma maneira simples (ou pelo menos viável) de conseguir isso com awk ou sed mas ainda não encontrei nenhum.

    
por greg118 22.03.2018 / 00:58

2 respostas

0

se o seu arquivo for um arquivo csv real (simple-csv) como abaixo, você pode usar o seguinte comando awk :

Entrada:

[email protected]
[email protected]
[email protected],[email protected],[email protected]

O comando:

awk -F, '{ COMMA="";i=0; while (++i<=NF) {
           $1=$i; printf (!seen[$1]++)?COMMA$i:""; COMMA=","}; print ""
}' infile.csv

Saída:

[email protected]
[email protected]
[email protected],[email protected]

Se não, e a entrada é como dar sua pergunta, você pode usar abaixo:

awk  'NR==1; NR>1{id=$1"\t"; COMMA=$1="";split($0, ar, /,| /); 
    for(i in ar){if(ar[i]!=""){printf(!seen[ar[i]]++)?id""COMMA""ar[i]:""; COMMA=",";id=""}
} print ""}' infile

Saída:

id  emails
1       [email protected]
2       [email protected]
3       [email protected],[email protected]
    
por 22.03.2018 / 01:55
1

Aqui está uma solução sed que funciona com o seu formato de entrada exato e que também corre rápido.

sed -rz 's:[ \t]+:,:g;s:$:,:mg;:l;s:,([^,]+),(.*),,:,,,:;tl;s:,$::mg;s:^([^,]+),:\t:mg' file.csv

Como funciona:

O sinalizador '-z' carrega o arquivo inteiro, então o código a seguir é aplicado uma vez, não em todas as linhas, como é por padrão.

#transform input format to actual CSV format
s:[ \t]+:,:g;s:$:,:mg;
#loop while the s command can still find and replace
:l;
    #main code: find two identical cell values anywhere and delete the latter
    #on a very big file this can suffer from backtracking nightmare
    s:,([^,]+),(.*),,:,,,:;
tl;
#transform format back
s:,$::mg;s:^([^,]+),:\t:mg
    
por 22.03.2018 / 10:16