2 votes

Comment trier une liste en utilisant grep pour afficher le nombre d'occurrences uniques en fonction d'une liste prédéfinie ?

Disons que j'ai une liste qui ressemble à ceci

exemple.txt :

2010-01-06 15:03:14 57.55.24.13 user1
2010-01-07 20:02:14 69.54.12.36 user2
2010-01-08 12:34:34 127.21.159.2 user3
2010-01-08 02:43:45 116.40.11.179 user1 

La liste contient un certain nombre d'utilisateurs donnés et les adresses IP qu'ils ont utilisées. Ce que je veux faire, c'est trouver le nombre d'adresses IP uniques à partir desquelles chaque utilisateur s'est connecté. Ainsi, dans l'exemple précédent, user1 renverrait la valeur 2. Cependant, si user1 se connectait à nouveau depuis 116.40.11.179, le résultat serait toujours 2 puisqu'il ne s'agit pas d'une adresse IP unique.

J'ai essayé de faire une liste de noms d'utilisateurs.

userlist.txt :

user1
user2
user3

Ensuite, j'essaie de le passer à grep avec quelque chose comme

grep example.txt | uniq -c | wc -l < userlist.txt

mais ça ne marche pas si bien que ça. Des idées ?

2voto

RavinderSingh13 Points 29608

Pourriez-vous essayer ce qui suit.

awk '
!seen[$NF OFS $(NF-1)]++{
  user[$NF]++
}
END{
  for(key in user){
    print key,user[key]
  }
}
'  Input_file

Le résultat sera le suivant.

user1 2                                                                                                                       
user2 1                                                                                                                       
user3 1

1voto

slitvinov Points 2661
awk '
{
    u = $4
    ip = $3
    if (!s[u,ip]++)
        cnt[u]++
}
END {
    for (u in cnt)
        print u, cnt[u]
}
' input.file

Sorties

user1 2
user2 1
user3 1

1voto

Ed Morton Points 25374

Avec GNU awk pour les tableaux de tableaux :

$ awk '{usrs_ips[$4][$3]} END{for (usr in usrs_ips) print usr, length(usrs_ips[usr])}' file
user1 2
user2 1
user3 1

Avec un awk qui supporte length(array) :

$ sort -k4,4 file | awk '
    $4 != prev {if (NR>1) print prev, length(ips); prev=$4; delete ips }
    { ips[$3] }
    END { print prev, length(ips) }
'
user1 2
user2 1
user3 1

Avec n'importe quel awk :

$ sort -k4,4 file | awk '
    $4 != prev { if (NR>1) print prev, cnt; prev=$4; delete seen; cnt=0 }
    !seen[$3]++ { cnt++ }
    END { print prev, cnt }
'
user1 2
user2 1
user3 1

Ces deux dernières solutions ont l'avantage, par rapport à la première et aux autres solutions proposées jusqu'à présent, de ne pas stocker chaque combinaison utilisateur+ip en mémoire, mais cela n'aurait d'importance que si votre fichier d'entrée était énorme.

1voto

Pierre François Points 1402

L'outil pour effectuer cette opération est uniq . Vous devez appliquer uniq deux fois : une première à temps pour regrouper les entrées de exemple.txt par utilisateur et IP, un second pour le comptage.

Il n'est donc pas nécessaire de le recoder dans AWK, même si cela peut être fait d'une très belle manière. J'utiliserai cependant AWK pour réordonner les champs :

awk '{print $4, $3}' example.txt | sort | uniq | awk '{print $1}' | uniq -c

Il n'est pas nécessaire de disposer d'un liste d'utilisateurs.txt fichier.

0voto

Shawn Points 13289

Un non awk par exemple, en utilisant GNU datamash est un outil très utile pour effectuer des opérations sur des groupes de données en colonnes comme celui-ci :

$ datamash -Ws -g4 countunique 3 < example.txt
user1   2
user2   1
user3   1

Pour chaque groupe ayant la même valeur dans la 4e colonne, il imprime le nombre d'occurrences uniques des valeurs dans la 3e colonne.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X