Antworten:
greps -ogibt nur die Übereinstimmungen aus und ignoriert die Zeilen. wckann 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
\bund \Bmacht man hier?
uniqentfernt nur benachbarte identische Zeilen, die Sie sortvor dem Füttern entfernen müssen, uniqwenn 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 sedund 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 ^needleoder \bneedlein needleneedle).
sed 's/needle/\n&\n/g' | grep -cx 'needle'
Beachten Sie, dass ich in den obigen sed-Substitutionen \neinen 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 needleals Feldtrenner:
awk -F'^needle | needle | needle$' '{c+=NF-1}END{print c}'
Wenn Sie eine Übereinstimmung needlegefolgt 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}'
grepes spezifiziert ist, aber für jedenack, der es benutzt , ist die Antwort einfachack -ch <pattern>.