Grep: compter le nombre de correspondances par ligne

26

J'essaie d'obtenir le nombre de correspondances (dans ce cas, les occurrences de {ou }) dans chaque ligne d'un fichier .tex.

Je sais que le -odrapeau ne renvoie que le match, mais il renvoie chaque match sur une nouvelle ligne, même combinée avec le -ndrapeau. Je ne sais rien de ce que je pourrais faire passer à travers pour compter les répétitions. L' -cindicateur ne renvoie que le nombre total de correspondances dans l'ensemble du fichier - peut-être que je pourrais diriger une ligne à la fois vers grep?

Chris H
la source

Réponses:

27
grep -o -n '[{}]' <filename> | cut -d : -f 1 | uniq -c

La sortie sera quelque chose comme:

3 1
1 2

Signification 3 occurrences dans la première ligne et 1 dans la seconde.

Tiré de /programming//a/15366097/3378354 .

Moebius
la source
Merci - Google a trouvé beaucoup de hits regex sur SU, mais pas celui sur SO, qui ne semble même pas avoir de tag regex. Ce sortn'est pas strictement nécessaire car la sortie de grep est triée par numéro de ligne, mais je suppose que c'est une bonne pratique avant uniq.
Chris H
2
Probablement pas étiqueté regexcar le regex est la partie facile.
Tom Zych
Est-ce vraiment nécessaire sort -n? Cela ne sort-il pas dans l'ordre des numéros de ligne de toute façon?
Tom Zych
Vous avez raison, ce sort -nn'est pas nécessaire. Merci.
Moebius
@ TomZych, il s'est avéré que vous aviez raison, mais si j'avais su que je n'aurais peut-être pas demandé. Le saut mental de grep à tag: regex était peut-être un peu trop cependant.
Chris H
3

Après avoir lu diverses solutions, je pense que c'est l'approche la plus simple au problème:

while read i; do echo $i |grep -o "matchingString"| wc -l;  done < input.txt
Alfredocambera
la source
3
La meilleure solution, à mon avis. Peut - être encore plus simplifiée en réduisant par un tuyau: grep -o "matchingString" <<< $i | wc -l.
Benjamin W.
1
Ce sera des ordres de grandeur plus lents que d'autres options
Rahul
1

Utilise grepune exigence? Voici une alternative:

sed 's / [^ {}] // g' votre_fichier | awk '{print NR, length}'

Le sedsupprime tous les caractères autres que {et } (c'est-à-dire ne laissant que les caractères {et }), puis le awkcompte les caractères sur chaque ligne (qui ne sont que les caractères {et }). Pour supprimer les lignes sans correspondance,

sed 's / [^ {}] // g' votre_fichier | awk '/./ {print NR, longueur}'

Notez que ma solution suppose (nécessite) que les chaînes que vous recherchez sont des caractères uniques. La réponse de Moebius est plus facilement adaptée aux chaînes multi-caractères. De plus, aucune de nos réponses n'exclut les occurrences citées ou échappées des caractères / chaînes d'intérêt; par exemple,

{ "nullfunc() {}" }

serait considéré comme contenant quatre accolades.

Scott
la source
grepCe n'était pas vraiment une exigence, c'était juste là où j'ai commencé à chercher une solution, car cela m'a donné quelque chose de proche. Je n'ai jamais eu besoin de awk, donc si je n'avais pas utilisé la réponse ci-dessus, j'aurais utilisé cela comme une chance d'expérimenter - je peux encore. Ce que je n'ai pas précisé (mais cela n'affecte pas l'une ou l'autre réponse), c'est que je voulais exécuter le script une fois par parenthèse, pour m'aider à trouver une disparité (dans la source LaTeX, ici pour un tableau) où la plupart des paires se produisent dans une seule ligne.
Chris H
Je ne sais pas trop ce que vous entendez par «exécuter le script une fois par parenthèse», mais si vous voulez dépister une non-concordance d'accolade, vous voudrez peut-être essayer quelque chose comme sed 's/{[^{}]*}//g' your_file | grep –n '[{}]', où les sedbandes hors (appariées) paires. Si vous avez des paires imbriquées, utilisez sed 's/{[^{}]*}//g;s/{[^{}]*}//g;s/{[^{}]*}//g;…' …, en répétant s/{[^{}]*}//gautant de fois que votre imbrication la plus profonde.
Scott
Je voulais dire exécuter `sed '/ [^}] // g' votre_fichier | awk '{print NR, length}' et 's / [^ {] // g' votre_fichier | awk '{print NR, length}'. J'ai effectivement des nids, et travailler au niveau le plus profond semblait être une corvée. Transformer plusieurs lignes en une poignée (il y a quelques cas où les accolades ne correspondent qu'à plusieurs lignes pour des raisons valables) a bien fonctionné (j'utilise jedit qui met en évidence le support correspondant - pour tout type de support qu'il comprend - donc je l'ai vraiment fait juste besoin de le réduire).
Chris H