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, dieack
verwenden, lautet die Antwort einfachack -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üssensort
eingeben, bevor Sieuniq
, 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.