Grep: policz liczbę dopasowań w linii

26

Próbuję uzyskać liczbę dopasowań (w tym przypadku wystąpień {lub }) w każdej linii pliku .tex.

Wiem, że -oflaga zwraca tylko dopasowanie, ale zwraca każde dopasowanie w nowej linii, nawet w połączeniu z -nflagą. Nie wiem nic, co mógłbym przelecieć, żeby policzyć powtórzenia. -cFlag zwraca tylko łączną liczbę meczów w całym pliku - może mógłbym rura jeden wiersz naraz grep?

Chris H.
źródło

Odpowiedzi:

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

Wynik będzie taki jak:

3 1
1 2

Oznacza to 3 wystąpienia w pierwszym wierszu i 1 w drugim.

Zaczerpnięte z /programming//a/15366097/3378354 .

Moebius
źródło
Dzięki - Google znalazło wiele trafień regularnych na SU, ale nie na SO, które nawet nie wydają się mieć znacznika regularnego. Nie sortjest to absolutnie konieczne, ponieważ wyjście grep jest sortowane według numeru linii, ale myślę, że wcześniej była to dobra praktyka uniq.
Chris H
2
Prawdopodobnie nie otagowano, regexponieważ wyrażenie regularne jest łatwą częścią.
Tom Zych
Czy to naprawdę konieczne sort -n? Czy to zresztą nie wynika z kolejności numerów?
Tom Zych,
Masz rację, sort -nnie jest to konieczne. Dzięki.
Moebius
@TomZych, okazało się, że masz rację, ale gdybym wiedział, że mógłbym nie zapytać. Mentalny skok z grep do tag: regex był jednak może trochę za duży.
Chris H
3

Po przeczytaniu różnych rozwiązań wydaje mi się, że jest to najłatwiejsze podejście do problemu:

while read i; do echo $i |grep -o "matchingString"| wc -l;  done < input.txt
alfredocambera
źródło
3
Moim zdaniem najlepsze rozwiązanie. Może być jeszcze bardziej uproszczone przez ograniczenie przez jedną rurę: grep -o "matchingString" <<< $i | wc -l.
Benjamin W.,
1
Będzie to o rząd wielkości wolniejsze niż inne opcje
Rahul
1

Czy używasz grepwymagań? Oto alternatywa:

sed 's / [^ {}] // g' twój_plik | awk „{drukuj NR, długość}”

Te sedpaski spośród wszystkich znaków innych niż {a } (czyli, pozostawiając tylko {i }znaków), a następnie awkzlicza znaki na każdej linii (które są tylko {i }znaków). Aby pominąć linie bez dopasowań,

sed 's / [^ {}] // g' twój_plik | awk ”/./ {print NR, length}”

Zauważ, że moje rozwiązanie zakłada (wymaga), że ciągi, których szukasz, to pojedyncze znaki. Odpowiedź Moebiusa jest łatwiej przystosowana do ciągów wieloznakowych. Ponadto żadna z naszych odpowiedzi nie wyklucza cytowanych lub unikniętych wystąpień znaków / ciągów zainteresowania; na przykład,

{ "nullfunc() {}" }

byłoby uważane za zawierające cztery znaki nawiasu klamrowego.

Scott
źródło
grepnie było tak naprawdę wymogiem, właśnie tam zacząłem szukać rozwiązania, ponieważ dało mi to coś bliskiego. Nigdy nie potrzebowałem awk, więc gdybym nie użył powyższej odpowiedzi, wykorzystałbym to jako okazję do eksperymentowania - być może nadal. Nie wyjaśniłem (ale nie wpływa to na żadną odpowiedź), że chciałem uruchomić skrypt raz na nawias, aby pomóc mi wyśledzić niedopasowanie (w źródle LaTeX, tutaj dla tabeli), w którym występuje większość par pojedyncza linia.
Chris H
Nie jestem do końca pewien, co rozumiesz przez „uruchamianie skryptu raz na nawias”, ale jeśli chcesz wyśledzić niedopasowanie nawiasów klamrowych, możesz spróbować czegoś takiego sed 's/{[^{}]*}//g' your_file | grep –n '[{}]', w którym sedpary pasują (dopasowane). Jeśli masz zagnieżdżone pary, użyj sed 's/{[^{}]*}//g;s/{[^{}]*}//g;s/{[^{}]*}//g;…' …, powtarzając s/{[^{}]*}//gtyle razy, ile jest najgłębsze zagnieżdżenie.
Scott
Miałem na myśli wykonanie `sed 's / [^}] // g' twój_plik | awk '{print NR, length}' i 's / [^ {] // g' twój_plik | awk „{print NR, length}”. Naprawdę mam zagnieżdżanie, a wypracowanie najgłębszego poziomu wydawało mi się obowiązkiem. Przekształcanie wielu linii w garść (istnieje kilka przypadków, w których nawiasy klamrowe pasują tylko do wielu linii z ważnych powodów) działało dobrze (używam jedit, który wyróżnia pasujący nawias - dla każdego rodzaju nawiasów, który rozumie - więc naprawdę to zrobiłem wystarczy go zawęzić).
Chris H