grep -c ist hilfreich, um festzustellen, wie oft eine Zeichenfolge in einer Datei vorkommt , aber es zählt jedes Vorkommen nur einmal pro Zeile. Wie zähle ich mehrere Vorkommen pro Zeile?

Ich suche etwas Eleganteres als:

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

Kommentare

  • Ich weiß, dass grep angegeben ist, aber für alle, die ack verwenden, lautet die Antwort einfach ack -ch <pattern>.
  • @KyleStrand Für mich ack -ch < pattern > zählte nur die Zeilen mit Vorkommen und nicht die Anzahl der Vorkommen
  • @MarcKees Auf der Manpage klingt das nach dem richtigen Verhalten. Vielen Dank, dass Sie darauf hingewiesen haben!

Antwort

grep „s -o gibt nur die Übereinstimmungen aus und ignoriert Zeilen. wc kann sie zählen:

grep -o "needle" file | wc -l 

Dies entspricht auch „Nadeln“ oder „Mehrnadeln“.

Um nur einzelne Wörter abzugleichen, verwenden Sie einen der folgenden Befehle:

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

Kommentare

  • Beachten Sie, dass hierfür GNU grep (Linux, Cygwin, FreeBSD, OSX) erforderlich ist.
  • @wag Welche Magie bewirkt \b und \B hier?
  • @Geek \ b entspricht einer Wortgrenze, \ B entspricht NICHT einer Wortgrenze. Die obige Antwort wäre korrekter, wenn an beiden Enden \ b verwendet würde.
  • Kombinieren Sie für eine Anzahl von Vorkommen pro Zeile die Option grep -n und uniq -c … grep -no ' \ < Nadel \ > ' Datei | uniq -c
  • @jameswarren uniq entfernt nur benachbarte identische Zeilen. Sie müssen sort eingeben, bevor Sie uniq, wenn Sie nicht bereits sicher sind, dass Duplikate immer unmittelbar nebeneinander liegen.

Antwort

Wenn Sie GNU grep haben (immer unter Linux und Cygwin, gelegentlich anderswo), können Sie die Ausgabezeilen von grep -o : grep -o needle | wc -l.

Mit Perl finde ich einige Möglichkeiten eleganter als deins (auch nachdem es behoben ).

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" 

Mit nur POSIX-Tools besteht ein Ansatz, wenn möglich, darin, das zu teilen Geben Sie in Zeilen mit einer einzelnen Übereinstimmung ein, bevor Sie sie an grep übergeben. Wenn Sie beispielsweise nach ganzen Wörtern suchen, verwandeln Sie zuerst jedes Nicht-Wort-Zeichen in eine neue Zeile.

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

Andernfalls gibt es keinen Standardbefehl, um dies zu tun s besonderes Stück Textverarbeitung, so müssen Sie sich an sed (wenn Sie „ein Masochist sind) oder awk wenden.

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 

Hier“ ist eine einfachere Lösung mit sed und grep, die für Zeichenfolgen oder sogar reguläre Ausdrücke funktionieren, jedoch in einigen Eckfällen mit verankerten Mustern fehlschlagen ( z.B Es werden zwei Vorkommen von ^needle oder \bneedle in needleneedle) gefunden.

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

Beachten Sie, dass ich in den obigen sed-Ersetzungen \n verwendet habe, um eine neue Zeile zu bezeichnen. Dies ist im Musterteil Standard, aber im Ersatztext ersetzen Sie aus Gründen der Portabilität \n durch

Answer

Wenn Sie wie ich tatsächlich „beide; jeweils genau einmal“, (dies ist eigentlich „entweder; zweimal“) wollten, dann ist es einfach :

grep -E "thing1|thing2" -c 

und überprüfen Sie die Ausgabe 2.

Der Vorteil dieses Ansatzes (wenn genau einmal ist, was Sie wollen) ist, dass es leicht skaliert werden kann.

Kommentare

  • I ' bin nicht sicher, ob Sie ' tatsächlich überprüfen, ob ' nur einmal angezeigt wird? Alles, was Sie ' suchen, dass eines dieser Wörter mindestens einmal existiert.
  • Dies sollte die akzeptierte Antwort sein. Es ist nicht erforderlich, , grep verfügt über eine integrierte Option zum Zählen von Dingen und wird sogar als offensichtlich bezeichnet als -c für „count“!

Antwort

Eine andere Lösung mit awk und needle als Feldtrennzeichen:

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

Wenn Sie mit gefolgt von Interpunktion, ändern Sie das Feldtrennzeichen entsprechend, dh

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

Oder verwenden Sie die Klasse: [^[:alnum:]], um alle Nicht-Alpha-Zeichen zu erfassen.

Kommentare

  • Beachten Sie, dass hierfür ein awk erforderlich ist, das Regexp-Feldtrennzeichen unterstützt (z. B. GNU awk).

Antwort

Dies ist meine reine Bash-Lösung

#!/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 

Antwort

In Ihrem Beispiel wird nur die Anzahl der Vorkommen pro Zeile und nicht die Summe in der Datei gedruckt. Wenn Sie dies möchten, funktioniert möglicherweise Folgendes:

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

Kommentare

  • Sie sind richtig – mein Beispiel zählt nur die Vorkommen in der ersten Zeile.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.