Antworten:
greps -o
gibt nur die Übereinstimmungen aus und ignoriert die Zeilen. wc
kann sie zählen:
grep -o 'needle' file | wc -l
Dies passt auch zu 'Nadeln' oder 'Mehrnadeln'.
Nur einzelne Wörter:
grep -o '\bneedle\B' file | wc -l
# or:
grep -o '\<needle\>' file | wc -l
\b
und \B
macht man hier?
uniq
entfernt nur benachbarte identische Zeilen, die Sie sort
vor dem Füttern entfernen müssen, uniq
wenn Sie nicht bereits sicher sind, dass Duplikate immer unmittelbar benachbart sind.
Wenn Sie GNU grep haben (immer unter Linux und Cygwin, gelegentlich an anderer Stelle), können Sie die Ausgangsleitungen von zählengrep -o
: grep -o needle | wc -l
.
Mit Perl gibt es einige Möglichkeiten, die ich eleganter finde als Ihre (auch nachdem sie behoben wurden ).
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'
Wenn nur POSIX-Tools verwendet werden, besteht eine Möglichkeit darin, die Eingabe mit einer einzelnen Übereinstimmung in Zeilen aufzuteilen, bevor sie an grep übergeben wird. Wenn Sie beispielsweise nach ganzen Wörtern suchen, wandeln Sie zuerst jedes Nicht-Wort-Zeichen in eine neue Zeile um.
# equivalent to grep -ow 'needle' | wc -l
tr -c '[:alnum:]' '[\n*]' | grep -c '^needle$'
Andernfalls gibt es keinen Standardbefehl für diese spezielle Textverarbeitung. Sie müssen sich daher 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 funktioniert, jedoch in einigen Eckfällen mit verankerten Mustern fehlschlägt (z. B. findet sie zwei Vorkommen von ^needle
oder \bneedle
in needleneedle
).
sed 's/needle/\n&\n/g' | grep -cx 'needle'
Beachten Sie, dass ich in den obigen sed-Substitutionen \n
einen Zeilenumbruch meinte. Dies ist Standard im Musterteil, aber im Ersetzungstext ersetzen Sie aus Gründen der Portabilität Backslash-Newline \n
.
Wenn Sie, wie ich, tatsächlich "beides, jedes genau einmal" wollten (dies ist tatsächlich "entweder; zweimal"), dann ist es ganz 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 .
Eine andere Lösung mit awk und needle
als Feldtrenner:
awk -F'^needle | needle | needle$' '{c+=NF-1}END{print c}'
Wenn Sie eine Übereinstimmung needle
gefolgt von Interpunktion wünschen , ändern Sie das Feldtrennzeichen entsprechend
awk -F'^needle[ ,.?]|[ ,.?]needle[ ,.?]|[ ,.?]needle$' '{c+=NF-1}END{print c}'
Oder verwenden Sie die Klasse [^[:alnum:]]
:, um alle Nicht-Alpha-Zeichen einzuschließen.
In Ihrem Beispiel wird nur die Anzahl der Vorkommen pro Zeile und nicht die Gesamtsumme in der Datei gedruckt. Wenn es das ist, was Sie wollen, könnte so etwas funktionieren:
perl -nle '$c+=scalar(()=m/needle/g);END{print $c}'
grep
es spezifiziert ist, aber für jedenack
, der es benutzt , ist die Antwort einfachack -ch <pattern>
.