Zählen Sie die Anzahl der Vorkommen eines Musters in einer Datei (auch in derselben Zeile).

94

Bei der Suche nach der Anzahl der Vorkommen einer Zeichenfolge in einer Datei verwende ich im Allgemeinen:

grep pattern file | wc -l

Dies findet jedoch aufgrund der Funktionsweise von grep nur ein Vorkommen pro Zeile. Wie kann ich suchen, wie oft eine Zeichenfolge in einer Datei angezeigt wird, unabhängig davon, ob sie sich in derselben oder in verschiedenen Zeilen befindet?

Was ist auch, wenn ich nach einem Regex-Muster suche, nicht nach einer einfachen Zeichenfolge? Wie kann ich diese zählen oder, noch besser, jedes Spiel in einer neuen Zeile drucken?

jrdioko
quelle

Antworten:

156

Verwenden Sie, um alle Vorkommen zu zählen -o. Versuche dies:

echo afoobarfoobar | grep -o foo | wc -l

Und man grepnatürlich (:

Aktualisieren

Einige schlagen vor, nur grep -co fooanstelle von zu verwenden grep -o foo | wc -l.

Tu es nicht.

Diese Verknüpfung funktioniert nicht in allen Fällen. Manpage sagt:

-c print a count of matching lines

Der Unterschied in diesen Ansätzen ist unten dargestellt:

1.

$ echo afoobarfoobar | grep -oc foo
1

Sobald die Übereinstimmung in der Zeile ( a{foo}barfoobar) gefunden wurde, wird die Suche beendet. Es wurde nur eine Zeile überprüft und sie stimmte überein, sodass die Ausgabe erfolgt 1. Eigentlich -owird hier ignoriert und man könnte grep -cstattdessen einfach verwenden .

2.

$ echo afoobarfoobar | grep -o foo
foo
foo

$ echo afoobarfoobar | grep -o foo | wc -l
2

In line ( a{foo}bar{foo}bar) werden zwei Übereinstimmungen gefunden, da wir ausdrücklich darum gebeten haben, jedes Vorkommen zu finden ( -o). Jedes Vorkommen wird in einer separaten Zeile gedruckt und wc -lzählt nur die Anzahl der Zeilen in der Ausgabe.

hudolejev
quelle
1
Wow ... ist es wirklich so einfach?
Jrdioko
1
grep -oc funktioniert in diesem Fall nicht. Versuchen Sie echo afoobarfoobar | grep -oc foo
Paulus
Gibt es keine Möglichkeit, dies für mehrere Dateien zu tun? Angenommen, ich möchte die Anzahl der Vorkommen pro Datei in einer Reihe von Dateien anzeigen. Ich kann es pro Zeile mit grep -c * machen, aber nicht pro Instanz.
Keith Tyler
grep -o foo a.txt b.txt | sort | uniq -cfunktioniert gut (mit GNU grep): gist.github.com/hudolejev/81a05791f38cbacfd4de3ee3b44eb4f8
hudolejev
2

Versuche dies:

grep "string to search for" FileNameToSearch | cut -d ":" -f 4 | sort -n | uniq -c

Stichprobe:

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]
IBrewThereforeIAm
quelle
1

Ein verspäteter Beitrag:
Verwenden Sie das Such-Regex-Muster als Datensatztrennzeichen (RS) in awk
Dies ermöglicht es Ihrem Regex, \nbegrenzte Linien zu überspannen (falls erforderlich).

printf 'X \n moo X\n XX\n' | 
   awk -vRS='X[^X]*X' 'END{print (NR<2?0:NR-1)}'
Peter.O
quelle
0

Ripgrep , eine schnelle Alternative zu grep, hat gerade das --count-matchesFlag eingeführt, mit dem jedes Match in Version 0.9 gezählt werden kann (ich verwende das obige Beispiel, um konsistent zu bleiben):

> echo afoobarfoobar | rg --count foo
1
> echo afoobarfoobar | rg --count-matches foo
2

Wie von OP gefordert, lässt ripgrep auch Regex-Muster zu ( --regexp <PATTERN>). Außerdem kann jede (Zeilen-) Übereinstimmung in einer separaten Zeile gedruckt werden:

> echo -e "line1foo\nline2afoobarfoobar" | rg foo
line1foo
line2afoobarfoobar
Sebastian Müller
quelle
-1

Hacken Sie die Farbfunktion von grep und zählen Sie, wie viele Farb-Tags gedruckt werden:

echo -e "a\nb  b b\nc\ndef\nb e brb\nr" \
| GREP_COLOR="033" grep --color=always  b \
| perl -e 'undef $/; $_=<>; s/\n//g; s/\x1b\x5b\x30\x33\x33/\n/g; print $_' \
| wc -l
Shizzmo
quelle