grep -c est utile pour trouver combien de fois une chaîne apparaît dans un fichier , mais il ne compte chaque occurrence quune fois par ligne. Comment compter plusieurs occurrences par ligne?

Je recherche quelque chose de plus élégant que:

perl -e "$_ = <>; print scalar ( () = m/needle/g ), "\n"" 

Commentaires

  • Je sais que grep est spécifié, mais pour toute personne utilisant ack, la réponse est simplement ack -ch <pattern>.
  • @KyleStrand For me ack -ch < motif > na compté que les lignes avec des occurrences et non le nombre doccurrences
  • @MarcKees En regardant la page de manuel, cela semble être le bon comportement. Merci de lavoir signalé!

Answer

grep « s -o affichera uniquement les correspondances, en ignorant les lignes; wc peut les compter:

grep -o "needle" file | wc -l 

Cela correspondra également à « aiguilles » ou « multi-aiguilles ».

Pour ne faire correspondre que des mots simples, utilisez lune des commandes suivantes:

grep -ow "needle" file | wc -l grep -o "\bneedle\b" file | wc -l grep -o "\<needle\>" file | wc -l 

Commentaires

  • Notez que cela nécessite GNU grep (Linux, Cygwin, FreeBSD, OSX).
  • @wag What magic does \b et \B faire ici?
  • @Geek \ b correspond à une limite de mot, \ B ne correspond PAS à une limite de mot. La réponse ci-dessus serait plus correcte si elle utilisait \ b aux deux extrémités.
  • Pour un nombre doccurrences par ligne, combinez avec loption grep -n et uniq -c … grep -no ' \ < aiguille \ > ' fichier | uniq -c
  • @jameswarren uniq ne supprime que les lignes identiques adjacentes, vous devez sort avant dalimenter uniq si vous nêtes pas déjà sûr que les doublons seront toujours immédiatement adjacents.

Réponse

Si vous avez GNU grep (toujours sous Linux et Cygwin, parfois ailleurs), vous pouvez compter les lignes de sortie de grep -o : grep -o needle | wc -l.

Avec Perl, voici quelques façons dont je trouve plus élégant que le vôtre (même après quil « s fixed ).

perl -lne "END {print $c} map ++$c, /needle/g" perl -lne "END {print $c} $c += s/needle//g" perl -lne "END {print $c} ++$c while /needle/g" 

Avec uniquement les outils POSIX, une approche, si possible, consiste à diviser entrée en lignes avec une seule correspondance avant de la transmettre à grep. Par exemple, si vous « recherchez des mots entiers, commencez par transformer chaque caractère autre quun mot en une nouvelle ligne.

# equivalent to grep -ow "needle" | wc -l tr -c "[:alnum:]" "[\n*]" | grep -c "^needle$" 

Sinon, il ny a pas de commande standard pour le faire s peu particulier de traitement de texte, donc vous devez vous tourner vers sed (si vous « êtes un masochiste) ou awk.

awk "{while (match($0, /set/)) {++c; $0=substr($0, RSTART+RLENGTH)}} END {print c}" sed -n -e "s/set/\n&\n/g" -e "s/^/\n/" -e "s/$/\n/" \ -e "s/\n[^\n]*\n/\n/g" -e "s/^\n//" -e "s/\n$//" \ -e "/./p" | wc -l 

Voici » une solution plus simple en utilisant sed et grep, qui fonctionne pour les chaînes ou même les expressions régulières par livre, mais échoue dans quelques cas de coin avec des motifs ancrés ( par exemple il trouve deux occurrences de ^needle ou \bneedle dans needleneedle).

sed "s/needle/\n&\n/g" | grep -cx "needle" 

Notez que dans les substitutions sed ci-dessus, jai utilisé \n pour signifier une nouvelle ligne. Ceci est standard dans la partie du motif, mais dans le texte de remplacement, pour la portabilité, remplacez \n.

Réponse

Si, comme moi, vous vouliez en fait « les deux; chacun exactement une fois », (cest en fait « soit; deux fois ») alors cest simple :

grep -E "thing1|thing2" -c 

et vérifiez la sortie 2.

Lavantage de cette approche (si exactement une fois est ce que vous voulez) cest quil sadapte facilement.

Commentaires

  • I ' Je ne suis pas sûr que ' est en train de vérifier que ' napparaît quune seule fois? Tous ' si vous recherchez, lun ou lautre de ces mots existe au moins une fois.
  • Cela devrait être la réponse acceptée. Pas besoin dutiliser wc -l, grep a une option intégrée pour compter les choses, et il est même nommé comme évident comme -c pour « count »!

Answer

Autre solution utilisant awk et needle comme séparateur de champ:

awk -F"^needle | needle | needle$" "{c+=NF-1}END{print c}" 

Si vous voulez faire correspondre needle suivi de la ponctuation, modifiez le séparateur de champ en conséquence, cest-à-dire

awk -F"^needle[ ,.?]|[ ,.?]needle[ ,.?]|[ ,.?]needle$" "{c+=NF-1}END{print c}" 

Ou utilisez la classe: [^[:alnum:]] pour englober tous les caractères non alpha.

Commentaires

  • Notez que cela nécessite un awk qui prend en charge les séparateurs de champs dexpression régulière (comme GNU awk).

Réponse

Ceci est ma solution pure bash

#!/bin/bash B=$(for i in $(cat /tmp/a | sort -u); do echo "$(grep $i /tmp/a | wc -l) $i" done) echo "$B" | sort --reverse 

Réponse

Votre exemple nimprime que le nombre doccurrences par ligne, et non le total dans le fichier. Si cest ce que vous voulez, quelque chose comme ça pourrait fonctionner:

perl -nle "$c+=scalar(()=m/needle/g);END{print $c}" 

Commentaires

  • Vous ont raison – mon exemple ne compte que les occurrences de la première ligne.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *