grep --before-context 5
zeigt 5 Zeilen vor dem Spiel.
Ich möchte alles vor dem Spiel zeigen.
Das grep --before-context 99999999
würde funktionieren, aber es ist nicht sehr ... professionell.
Wie zeige ich die gesamte Datei bis zum Spiel an?
grep --before-context 5
zeigt 5 Zeilen vor dem Spiel.
Ich möchte alles vor dem Spiel zeigen.
Das grep --before-context 99999999
würde funktionieren, aber es ist nicht sehr ... professionell.
Wie zeige ich die gesamte Datei bis zum Spiel an?
Antworten:
Sed ist besser dafür.
Mach einfach:
sed '/PATTERN/q' FILE
Das funktioniert so:
Wir prüfen für jede Zeile, ob sie übereinstimmt /PATTERN
:
Dies ist die effizienteste Lösung, da PATTERN
sie beendet wird, sobald sie angezeigt wird. Ohne q
würde sed den Rest der Datei weiterhin lesen und nichts damit anfangen. Bei großen Dateien kann dies einen Unterschied machen.
Dieser Trick kann auch verwendet werden, um Folgendes zu emulieren head
:
sed 10q FILE
sed '/PATTERN/Q' FILE
überspringt die übereinstimmende Zeile. Q
ist eine GNU-Erweiterung, daher funktioniert sie mit keinem sed.
sed
kann die meisten Funktionen von grep ersetzen.
sed -n '1,/<pattern>/ p' <file>
Dies bedeutet, dass ab der ersten Zeile gedruckt wird, bis das Muster übereinstimmt.
Einige Beispiele
sed -n '/<pattern>/,$ p' <file> # from pattern to end of file
sed -n '/<pattern1>/,/<pattern2>/ p' <file> # from pattern1 to pattern2
drucke bis und mit dem match:
awk '{print} /pattern/ {exit}' filename
sed '/pattern/q' filename
drucke bis ABER OHNE das Streichholz:
awk '/pattern/ {exit} {print}' filename
sed '/pattern/Q' filename
Q
ist cool aber gnu spezifisch afaik, sed -n '/pattern/!p;//q'
wäre portabler.
!
macht p
zutreffende linien nicht passend pattern
, aber dann //q
verwirrt mich das ...
//
bedeutet "vorheriger regulärer Ausdruck" (ich dachte, es bedeutet "mit der leeren Zeichenkette übereinstimmen"). Ich denke, eine kürzere Version der gleichen Lösung ist sed -n '/pattern/q;p
:?
Die folgenden reinen GNU- grep
Methoden sind nicht effizient.
Suchen Sie nach allem bis zur ersten Instanz von String „ foo “ in der Datei bar , mit drei grep
s:
grep -m 1 -B $(grep -n -m 1 foo bar | grep -o '^[0-9]*') foo bar
Matching bis zur letzten Instanz von " foo ":
grep -oPz "(?s)[^\n]*${s}.*?\n.*?foo.*?\n" bar
Hinweis: Details zum letzten grep
finden Sie in: Regex (grep) für mehrzeilige Suche erforderlich .
grep
s (+ pcre) verwenden wollen, wenn es nur darum geht, einen einzelnen sed
Aufruf auszuführen : sed 'x;/./G;//!x;/foo/p;//s/.*//;x;d'
??
sed
Code scheint eine eigene Antwort wert zu sein oder könnte zu einem der anderen hinzugefügt werden. Zu 7 grep
s: Weil es keine grep
Antwort gab ... (Plus, die Antwort zeigt, warum nicht.)
Hinzufügen zu Mikel's Antwort oben ...
Versuchen Sie Folgendes , um alle Zeilen bis zur ersten Zeile des FILE
Inhalts zu drucken , ohne diesePATTERN
einzuschließen:
sed '/.*PATTERN.*/{s///;q;}' FILE
Dies stimmt mit der gesamten Zeile überein, die das Muster enthält, ersetzt es durch eine leere Zeile und wird dann beendet, ohne den Rest der Datei zu verarbeiten.
Nachsatz:
Der einfachste / klarste Weg, um zu verhindern, dass am Ende eine zusätzliche neue Zeile gedruckt wird (ohne ein anderes Tool zu verwenden), war, sed erneut auszuführen und die neue letzte Zeile zu löschen:
sed '/.*PATTERN.*/{s///;q;}' FILE | sed '$d'
... und da wir diese Zeile jetzt sowieso löschen, ist unsere bisherige Arbeit überflüssig und wir können Folgendes vereinfachen:
sed '/PATTERN/q' FILE | sed '$d'
sed
Aufruf macht.
tcsh
als auch in einem bash
Alias verwendet habe, musste ich sicherstellen, dass ich hatte eine relativ prägnante einzeilige Lösung, die sowohl in Standard als auch in GNU sed
(für Portabilität) funktionierte ; alle anforderungen, die ihr beitrag sehr wohl erfüllt haben könnte. Als jemand, der sed
sehr selten verwendet, war meine wichtigste Anforderung etwas, das ich schnell verstehen konnte, wenn ich es in Jahren einfach bearbeiten oder neu verwenden möchte.
Für Menschen, die sich bei der täglichen Arbeit nur an die grundlegenden Tools erinnern und weniger elegante und weniger effiziente Lösungen akzeptieren möchten:
head -n $(grep -n pattern filename | cut -d: -f1) filename
Wenn dieser Befehl für ein Skript bestimmt ist, suche ich nach eleganteren (und möglicherweise effizienteren) Lösungen. Wenn dies ein einmaliger Befehl oder ein Wegwerfskript ist, ist es mir egal.
Sie können auch eine der folgenden Optionen verwenden
tac ./test | grep -B $(cat ./test | wc -l) -m 1 'pattern'|tac
oder
tac ./test |head -n $(tac ./test | grep -n 'pattern' | cut -d: -f1 | head -n 1)|tac
oder
tac ./test |sed ':a;N;$!ba;s/\n/'"pattern"'/g' | sed 's/'"patternpattern"'/\n/g'|head -n 1|sed 's/'"pattern"'/\n/g'|tac
Die erste Option ist der vom OP vorgeschlagenen sehr ähnlich, stellt jedoch sicher, dass vor dem Kontext genügend Zeilen angezeigt werden, indem die Zeilen in der Datei gezählt werden
Die zweite Option durchsucht die Zeilennummer der ersten Übereinstimmung (Sie können dies auch ändern, indem Sie den inneren "Kopf" ändern) und verwendet dann den Kopf für diese Nummer
Die letzte Option ersetzt alle neuen Zeilen durch die Übereinstimmung und anschließend zwei benachbarte Übereinstimmungen durch eine neue Zeile. Die Ausgabe ist eine Zeile für jeden Textblock zwischen zwei Übereinstimmungen. Danach wählt es mit 'head' die erste Zeile (die den Textblock bis zur ersten Übereinstimmung abdeckt) und übersetzt dann jede Übereinstimmung erneut in eine neue Zeile. Diese Option funktioniert nur, wenn die Datei im folgenden Format vorliegt
pattern
texttexttext
texttexttext texttexttext
texttexttexttexttexttexttexttexttext
pattern
texttexttext
pattern
texttexttext
texttexttexttexttexttexttexttexttext
und so weiter
sed
Befehle funktionieren, vor allem, weil der Befehl unten ziemlich knorrig ist.