Wie kann das Auftreten einer bestimmten Zeichenfolge in einer bestimmten Zeile in einer Datei gezählt werden?

7

Ich weiß, dass ich wc verwenden kann, um die Gesamtzahl der Wörter (und Zeilen) in einer Datei zurückzugeben, indem ich:

wc <filename>

Gibt es eine Möglichkeit, die Anzahl für eine bestimmte Zeichenfolge in einer bestimmten Zeile einer Datei wie folgt zurückzugeben:

wc <filename> -<flag> <line number> -<flag> <string> 
Don P.
quelle

Antworten:

10

Dies muss in drei Schritten erfolgen:

  1. Wählen Sie die Zeilennummer N (Beispiel verwendet Zeile 42):

    sed '42!d'
    
  2. Durchsuchen Sie die Zeile nach allen Vorkommen eines bestimmten Musters (hier die Zeichenfolge / der reguläre Ausdruck hello) und drucken Sie diese separat aus:

    grep -o 'hello'
    
  3. Zähle die Übereinstimmungen:

    wc -l
    

Oder um es in eine einzige Befehlspipe zu schreiben: Lesen Sie aus file.txt:

sed '42!d' file.txt | grep -o 'hello' | wc -l
Byte Commander
quelle
1
grep hat einen
Zählmodus
2
@hildred grep's -czählt übereinstimmende Zeilen - nicht viel Sinn , um die Anzahl der übereinstimmenden Zeichenfolgen in einer einzelnen Zeile zu erhalten
steeldriver
Wenn Sie diese Zeile mit sed in mehrere Zeilen aufteilen, kann grep -c problemlos verwendet werden
Sergiy Kolodyazhnyy
@SergiyKolodyazhnyy, aber dann würden Sie sich alle Mühe geben, um etwas zu erfinden. Die Unix-Philosophie sieht vor, dass Programme fokussiert und zusammensetzbar sind. grepdient zum Suchen und wczum Zählen. Sie zu komponieren ist natürlicher, und daran ist nichts auszusetzen.
JoL
@jlmg Es gibt nichts Besonderes an einem solchen Ansatz. Das Herausnehmen und Aufteilen einer Zeile in mehrere Zeilen widerspricht in keiner Weise der Unix-Philosophie. sedmacht seinen Job, grepmacht seinen Job, und wir reihen sie nur aneinander. Siehe meine Antwort, ich fügte dies als Lösung hinzu
Sergiy Kolodyazhnyy
8

Dies ist ein guter Anwendungsfall, um Unix-Tools in einer Pipeline zusammenzustellen.

line=5
str="ipsum"
sed -n "${line}p" filename | grep -o -- "$str" | wc -l

Der pBefehl sed gibt die angegebene Zeile der Datei aus und führt sie in grep ein. Die -oOption von Grep weist an, alle Übereinstimmungen für die angegebene Zeichenfolge auszugeben, und jede Übereinstimmung wird in einer separaten Zeile ausgegeben. Die Ausgabe von Grep wird an wc weitergeleitet, wodurch die Anzahl der Zeilen gezählt wird.

Mark Plotnick
quelle
7

Python

Hier ist eine Möglichkeit, dies in Python über das Listenverständnis zu tun (siehe unten für eine alternative kürzere Version).

$ python -c 'import sys;print([ l for i,l in enumerate(sys.stdin,1) if i==2][0].count("word"))' < input.txt                                          
3
$ cat input.txt
nothing here
word and another word, and one more word
last line

So funktioniert das:

  • Wir führen den Python-Interpreter mit -cFlag aus, wobei Befehle in einfachen Anführungszeichen enthalten sind.
  • Die Eingabedatei input.txtwird stdinüber den <Shell-Operator in den Stream des Python-Interpreters umgeleitet . Daher brauchen wir ein sysModul.
  • Unter Verwendung der Listenverständnisstruktur [something for item in something]lesen wir Textzeilen aus sys.stdin.
  • enumerate(sys.stdin,1)ermöglicht es uns, die Zeilen zu zählen, dh mit jeder Iteration des Listenverständnisses erhalten wir die Textzeile in eine lVariable und einen Index in eine iVariable, beginnend mit der Zählung bei 1.
  • Das i==2filtert nur die Zeile heraus, deren Index gleich 2 ist. So wissen wir, welche Zeile extrahiert werden muss.
  • Daher enthält unsere Liste nur ein Element, und innerhalb der Liste befindet sich der Index 0. Wir bezeichnen diesen Artikel also als [<list comprehension stuff here>][0]. -Das .count("word")ist es, was eigentlich das Zählen macht. Per Definition gibt es eine Reihe von nicht überlappenden Vorkommen eines Teilstrings in einer Zeichenfolge zurück.
  • Schließlich war all dieses Zeug in der print()Aussage enthalten. Welche Zahl die .count()Methode zurückgibt, wird auf dem Bildschirm angezeigt.

Kürzere Version

Die kürzere Möglichkeit, dies in Python zu tun, besteht darin readlines(), anstelle des Listenverständnisses eine Methode zu verwenden und auf ein bestimmtes Element in der Liste zu verweisen, das readlines()erstellt wird. Beachten Sie, dass dadurch readlines()eine Liste erstellt wird und Listen in Python 0-indiziert sind. Wenn Sie also Zeile x lesen möchten, sollten Sie auf das Listenelement x-1 verweisen. Zum Beispiel,

$ python -c 'import sys;print(sys.stdin.readlines()[1].count("word"))' < input.txt       
3

sed + grep

Natürlich müssen wir uns nicht nur an Skriptsprachen halten. sedund grepstellen Sie ausreichende Werkzeuge zur Verfügung, die wir für unsere Bedürfnisse verwenden können. Mit können grep -cwir das Auftreten übereinstimmender Zeilen zählen. Wir müssen also nur die spezifische Zeile extrahieren, die wir benötigen, und alle Wörter in dieser Zeile in separate Zeilen aufteilen. Wie so:

$ sed -n  '2{s/ /\n/g;p}' input.txt | grep -c 'word'
3
Sergiy Kolodyazhnyy
quelle
Warum lesen Sie aus, sys.stdinanstatt nur die Datei in Python mit zu öffnen open("input.txt")?
Byte Commander
@ByteCommander kein besonderer Grund. Das kann man auch machen. Obwohl open()macht die Linie etwas länger. Es gibt jedoch keinen besonderen Vorteil
Sergiy Kolodyazhnyy
2
python -c 'n,w,f=2,"word",open("input.txt");[f.readline()for _ in range(n-1)];print(f.readline().count(w))'wäre mein persönlicher vorschlag.
Byte Commander
@ByteCommander zu Ihrem ersten Kommentar: Wahrscheinlich, weil das Nichtaufrufen der closeMethode für das Ergebnis von openein Speicherverlust ist?
Katze
1
@jlmg der Python wird man mit Leerzeichen arbeiten, sed + grep wird man nicht, stimmte dort zu
Sergiy Kolodyazhnyy
6

awk Lösung:

awk 'NR==X { print gsub("word",""); }' file
  • Ändern Sie die Xmit Ihrer spezifischen Zeilennummer.
  • Ändern Sie das "Wort" mit Ihrem gewünschten Wort.
  • gsub Gibt die Anzahl der Ersetzungen des "Wortes" zurück. Es sieht so aus, als würden wir es zählen.

Beispiel:

$ cat file:
a b c a a d
d e f f f 1

Mal sehen, wie viele 'f' wir in Zeile "2" haben:

$ awk 'NR==2 { print gsub("f",""); }' file
3
Ravexina
quelle
5

Eine Möglichkeit, dies zu tun perl:

perl -lne '
  BEGIN{($lineno, $str) = splice @ARGV,0,2} 
  print $c = () = /$str/g if $. == $lineno
' <lineno> <string> <filename>
Steeldriver
quelle