Lors de la recherche du nombre d'occurrences d'une chaîne dans un fichier, j'utilise généralement:
grep pattern file | wc -l
Cependant, ceci ne trouve qu'une occurrence par ligne, en raison du fonctionnement de grep. Comment puis-je rechercher le nombre de fois qu'une chaîne apparaît dans un fichier, qu'ils soient sur la même ligne ou sur des lignes différentes?
De plus, que se passe-t-il si je recherche un motif regex, pas une simple chaîne? Comment puis-je les compter ou, mieux encore, imprimer chaque match sur une nouvelle ligne?
Pour compter toutes les occurrences, utilisez -o
. Essaye ça:
echo afoobarfoobar | grep -o foo | wc -l
Et man grep
bien sûr (:
Certains suggèrent d'utiliser uniquement grep -co foo
au lieu de grep -o foo | wc -l
.
Ne pas.
Ce raccourci ne fonctionnera pas dans tous les cas. La page de manuel dit:
-c print a count of matching lines
La différence entre ces approches est illustrée ci-dessous:
1.
$ echo afoobarfoobar | grep -oc foo
1
Dès que la correspondance est trouvée dans la ligne (a{foo}barfoobar
), la recherche s'arrête. Une seule ligne a été vérifiée et correspond, le résultat est donc 1
. En fait, -o
est ignoré ici et vous pouvez simplement utiliser grep -c
à la place.
2.
$ echo afoobarfoobar | grep -o foo
foo
foo
$ echo afoobarfoobar | grep -o foo | wc -l
2
Deux correspondances sont trouvées dans la ligne (a{foo}bar{foo}bar
) car nous avons explicitement demandé de trouver chaque occurrence (-o
). Chaque occurrence est imprimée sur une ligne distincte et wc -l
ne compte que le nombre de lignes de la sortie.
Essaye ça:
grep "string to search for" FileNameToSearch | cut -d ":" -f 4 | sort -n | uniq -c
Échantillon:
grep "SMTP connect from unknown" maillog | cut -d ":" -f 4 | sort -n | uniq -c
6 SMTP connect from unknown [188.190.118.90]
54 SMTP connect from unknown [62.193.131.114]
3 SMTP connect from unknown [91.222.51.253]
Un post tardif:
Utilisez le modèle regex de recherche comme séparateur d’enregistrements (RS) dans awk
Cela permet à votre expression rationnelle d’étendre sur __ lignes de code \n
- (si vous en avez besoin).
printf 'X \n moo X\n XX\n' |
awk -vRS='X[^X]*X' 'END{print (NR<2?0:NR-1)}'
Ripgrep , qui est une alternative rapide à grep, vient de présenter le drapeau --count-matches
permettant de compter chaque correspondance dans la version 0.9 (j'utilise l'exemple ci-dessus pour rester cohérent):
> echo afoobarfoobar | rg --count foo
1
> echo afoobarfoobar | rg --count-matches foo
2
Comme demandé par OP, ripgrep autorise également le motif regex (--regexp <PATTERN>
) . Il peut également imprimer chaque correspondance (ligne) sur une ligne distincte:
> echo -e "line1foo\nline2afoobarfoobar" | rg foo
line1foo
line2afoobarfoobar