Wie kann ich die Anzahl der Zeilen in einer Datei nach einer Grep-Übereinstimmung zählen?

14

Ich versuche, die Anzahl der Zeilen nach einer problematischen Zeile in einer CSV-Datei zu zählen. Ich bin mir bewusst, dass ich die grep -a #Syntax verwenden kann, um die Anzahl der Zeilen auszugeben, nachdem eine Übereinstimmung gefunden wurde. Mich interessiert nur die tatsächliche Anzahl der Leitungen. Mir ist klar, dass ich die Zahl auf MAX_INT setzen, in eine Datei umleiten und etwas mehr verarbeiten könnte.

Ich bin auf der Suche nach einem prägnanten Einzeiler, der mir nur die Zählung angibt.

Irgendwelche Vorschläge?

NathanChristie
quelle

Antworten:

15
{ grep -m1 match; grep -c ''; } <file

Das wird mit GNU grepund einer lseek()fähigen Datei funktionieren. Der erste grepstoppt um 1 -mUhr und der zweite -czählt jede Zeile, die in der Eingabe verbleibt.

Ohne GNU grep:

{ sed '/match/q'; grep -c ''; } <file

Natürlich grepkönnen Sie auch alle anderen Optionen verwenden, und es ist überhaupt nicht erforderlich, bei einem Spiel anzuhalten.

mikeserv
quelle
Beides druckt auch die Zeile, und die zweite druckt bis zur ersten Übereinstimmung und dann 0 für mich?
123,
@ User112638726 - Sie können den Ausdruck des ersten Matches grep -m1 match >/dev/nullnatürlich mit löschen . Und Ihr zweites Problem ist eine GNU sed- sie setzt ihren Eingangsoffset nicht gemäß Spezifikation zurück. Sie müssen -uw / GNU verwenden - was nicht immer wünschenswert ist. Ich hätte klarer sein können, aber meine Annahme war, dass eine GNU grepund eine GNU sedpaarweise kommen würden. Ich denke, grep -qm1könnte auch funktionieren, um die /dev/nullWeiterleitung zu verkürzen - aber GNU grepmacht seltsame Dinge, -qund ich kann mich nicht erinnern, wie diese beiden zusammenarbeiten.
mikeserv
1
Schöne Antwort - zeigt wirklich die Macht der Befehlsgruppierungen. Ich weiß es nicht genau, aber ich denke, es wc -list ein bisschen billiger als grep -c ''.
Digital Trauma
1
@DigitalTrauma - Ja, ich habe darüber nachgedacht (im Nachhinein) , aber ich hatte es bereits geschrieben und es hat sich fast gereimt, also dachte ich mir, ich würde es gut genug in Ruhe lassen. Und trotzdem hast du es auch gesagt, also schlafe ich jetzt ruhig.
mikeserv
9

Hier ist ein Weg.

$ cat foo
aaa
bbb
ccc
ddd
eee
fff
$ awk '/^ddd/{a=FNR}END{print FNR-a}' foo
2
$
Steve
quelle
4
das ist kein codegolf, kannst du details angeben (FNR, END und so weiter)?
Archemar
3
Sicher. awk verwendet FNR, um die eingegebene Datensatznummer zu identifizieren. END ist der Code, der beim Erreichen des Dateiendes ausgeführt wird. Wenn also eine Übereinstimmung gefunden wird, wird die aktuelle Datensatznummer aufgezeichnet. Bei Erreichen des Dateiendes wird diese Zahl von der Gesamtzahl der Zeilen in der Datei abgezogen.
Steve
1
Kann auch einfach NR verwenden, da es eine Datei ist.
123,
6

Ein anderer Weg - Verwendung von dcist ein wenig esoterisch, scheint aber hier gut zu funktionieren:

sed -n '/problem/=;$=' prob.txt | dc -e '??r-p'

sedSucht prob.txtnach "Problem" und der letzten Zeile und gibt mit dem =Befehl die Zeilennummer von beiden aus.

dc Liest diese beiden Werte auf den Stapel, kehrt sie um, subtrahiert und druckt die Differenz.

Digitales Trauma
quelle
5

Ganz mit sed (wenn auch zwei Kommandos mit einer Pipe)

sed '/ddd/,$!d' file | sed -n '$='

Löscht alle Zeilen vor der Zeile und zählt dann mit dem nächsten Befehl die Zeilen in der neuen Datei.

123
quelle
3

Dies sollte alle Zeilen bis (und einschließlich) der problematischen Zeile löschen und dann die verbleibenden Zeilen zählen:

sed '1,/problem/d' data.txt | wc -l
Gast
quelle
1
(vorausgesetzt, "Problem" ist nicht in der ersten Zeile)
Stéphane Chazelas