Remover linhas duplicadas com uma torção [duplicada]

4

Ok, então eu quero remover linhas duplicadas, mas é um pouco mais complicado do que isso ...

Eu tenho um arquivo chamado users.txt, o exemplo do arquivo é:

 users:[email protected]
 users1:[email protected]

Agora, devido a um bug no meu sistema, as pessoas puderam se registrar com o mesmo e-mail de outra pessoa. Por isso, desejo remover se as linhas tiverem o mesmo e-mail mais de uma vez, como exemplo:

 user:display:[email protected]
 user2:[email protected]
 user3:[email protected]
 user4:[email protected]

Observe como usuário, usuário2, usuário3, usuário4 todos têm o mesmo email. bem, eu quero remover usuário2, usuário3, usuário4 mas manter usuário .. ou vice-versa (primeiro a ser atendido por solicitação) remover qualquer outro linhas contendo o mesmo email ..

então se

 [email protected] is in 20 lines remove 19
 [email protected] is in 555 lines remove 554
 and so fourth..
    
por yolo 02.03.2017 / 00:45

2 respostas

4

Isto pede o Awk. Como o campo que você deseja verificar é o primeiro campo de cada linha, apenas faça referência a $1 .

awk -F: '! ($1 in seen) {print; seen[$1]}' users.txt

Você pode "jogar golfe" para reduzi-lo consideravelmente:

awk -F: '!a[$1]++' users.txt

A forma mais longa é mais ou menos autoexplicativa; você constrói um array associativo usando cada endereço de email como um índice, sem se preocupar em atribuir um valor. Em seguida, você pode apenas verificar se o endereço de e-mail foi "visto" antes (ou seja, se o array associativo já tem um endereço de e-mail específico como um índice) e imprima a linha inteira, se não.

A forma mais curta está realmente fazendo mais ou menos a mesma coisa, mas requer mais explicações para o código mais curto.

O operador ++ do postfix atua em uma variável após a expressão é avaliada, então voltaremos a isso mais tarde.

No Awk, 0 significa falso e diferente de zero significa verdadeiro. ! é para negação e inverte o valor de verdade.

Aparecendo como fora das chaves, a expressão é interpretada como uma expressão booleana, com uma ação associada (entre chaves) a ser executada se a expressão for verdadeira. Como nenhuma ação é explicitamente declarada, a ação padrão (implícita) de imprimir a linha inteira é usada, se a expressão for avaliada como verdadeira (diferente de zero).

Essencialmente, isso recupera o valor na matriz associativa a que é apontada como o endereço de e-mail (primeiro campo) como seu índice - ou cria esse valor inicializado como 0 se ainda não estiver presente, interpreta um 0 como falso ou diferente de zero como verdadeiro, inverte esse valor de verdade e imprime toda a linha se o resultado for "verdadeiro" e, em seguida, incrementa o valor armazenado no array associativo nesse ponto.

Uma linguagem Awk bastante comum, na verdade, mas eu não culparia você por usar a versão mais explícita. :)

    
por 02.03.2017 / 00:55
2
  1. Use o GNU datamash para agrupar as entradas pelo , e mantenha apenas a primeira linha de cada agrupamento:

    datamash -t':' -g 2 rmdup 2 < users.txt
    
  2. Como um comentário das notas don_crissti , sort pode fazer isso, mas enquanto retorna os resultados desejados, ele também pode reordenar a saída:

    sort -t':' -k 2,2 -u users.txt
    

O código acima assume que users.txt é classificado pelo segundo campo e, em seguida, pelo primeiro campo.

    
por 02.03.2017 / 05:25