Ich habe eine Datei mit ungefähr 1000 Zeilen. Ich möchte den Teil meiner Datei nach der Zeile, die meiner grep-Anweisung entspricht.
Das ist:
$ cat file | grep 'TERMINATE' # It is found on line 534
Ich möchte also die Datei von Zeile 535 bis Zeile 1000 zur weiteren Verarbeitung.
Wie kann ich das machen?
grep 'TERMINATE' file
grep
Standardeingabeschnittstelle zum Einlesen von Daten verwenden können, anstatt lernen zu müssen, auf welchen Schaltergrep
undsed
, undawk
, undpandoc
undffmpeg
usw. angewendet werden sollen , wenn wir lesen möchten aus einer Datei. Das spart Zeit, da wir nicht jedes Mal einen neuen Schalter lernen müssen, wenn wir dasselbe tun möchten: Aus einer Datei lesen.grep 'TERMINATE' < file
. Vielleicht macht es das Lesen ein bisschen schwieriger - aber das ist Shell-Scripting, also wird das immer ein Problem sein :)Antworten:
Im Folgenden wird die Zeilenübereinstimmung
TERMINATE
bis zum Ende der Datei gedruckt :Erklärt:
-n
Deaktiviert das Standardverhaltensed
beim Drucken jeder Zeile nach dem Ausführen des Skripts.-e
Gibt ein Skript ansed
,/TERMINATE/,$
ist eine Auswahl des Adressbereichs (Zeile), dh die erste Zeile entspricht demTERMINATE
regulären Ausdruck (wie grep) am Ende der Datei ($
). undp
ist der Druckbefehl, der die aktuelle Zeile druckt.Dies wird von der Zeile gedruckt, die auf die Zeilenübereinstimmung folgt,
TERMINATE
bis zum Ende der Datei:(von NACH der übereinstimmenden Zeile bis EOF, ohne die übereinstimmende Zeile)
Erklärt:
1,/TERMINATE/
ist eine Adressbereichsauswahl (Zeile), die die erste Zeile für die Eingabe in die erste Zeile darstellt, die demTERMINATE
regulären Ausdruck entspricht, undd
ist der Löschbefehl, der die aktuelle Zeile löscht und zur nächsten Zeile springt. Da dassed
Standardverhalten darin besteht, die Zeilen zu drucken, werden die Zeilen nachTERMINATE
dem Ende der Eingabe gedruckt .Bearbeiten:
Wenn Sie die Zeilen vorher wollen
TERMINATE
:Und wenn Sie beide Zeilen vorher und nachher
TERMINATE
in 2 verschiedenen Dateien in einem Durchgang haben möchten :Die Vorher- und Nachher-Dateien enthalten die Zeile mit terminate. Um jede zu verarbeiten, müssen Sie Folgendes verwenden:
Edit2:
Wenn Sie die Dateinamen im sed-Skript nicht fest codieren möchten, können Sie:
Aber dann müssen Sie die
$
Bedeutung der letzten Zeile umgehen, damit die Shell nicht versucht, die$w
Variable zu erweitern (beachten Sie, dass wir jetzt doppelte Anführungszeichen um das Skript anstelle von einfachen Anführungszeichen verwenden).Ich habe vergessen zu sagen, dass die neue Zeile nach den Dateinamen im Skript wichtig ist, damit sed weiß, dass die Dateinamen enden.
Bearbeiten: 2016-0530
Sébastien Clément fragte: "Wie würden Sie das Hardcodierte
TERMINATE
durch eine Variable ersetzen ?"Sie würden eine Variable für den passenden Text erstellen und dann auf die gleiche Weise wie im vorherigen Beispiel vorgehen:
So verwenden Sie eine Variable für den übereinstimmenden Text mit den vorherigen Beispielen:
Die wichtigsten Punkte beim Ersetzen von Text durch Variablen in diesen Fällen sind:
$variablename
Insingle quotes
['
] eingeschlossene Variablen ( ) werden nicht "erweitert", Variablen indouble quotes
["
] jedoch. Sie müssen also alle in ändernsingle quotes
,double quotes
wenn sie Text enthalten, den Sie durch eine Variable ersetzen möchten.sed
Bereiche auch enthalten$
und werden unmittelbar gefolgt von einem Buchstaben wie:$p
,$d
,$w
. Sie werden auch wie Variablen aussehen erweitert werden, so dass Sie diese fliehen müssen , um$
Zeichen mit einem Backslash [\
] wie:\$p
,\$d
,\$w
.quelle
sed -e "1,/$matchtext/d"
funktioniert nicht, wenn$matchtext
es in der ersten Zeile auftritt. Ich musste es ändernsed -e "0,/$matchtext/d"
.Als einfache Annäherung könnten Sie verwenden
Hiermit werden
TERMINATE
bis zu 100000 Zeilen erfasst und ausgegeben, die dieser Zeile folgen.Von der Manpage
quelle
file
stattdessen die Zeilen zählen :grep -A$(cat file | wc -l) TERMINATE file
Ein hier zu verwendendes Tool ist awk:
Wie funktioniert das:
Die anderen Lösungen verbrauchen möglicherweise viel Speicher, wenn Sie sie für sehr große Dateien verwenden.
quelle
cat file | awk 'BEGIN{ found=0} /###/{found=found+1} {if (found<2) print }'
cat
.awk
ist perfekt in der Lage, einen oder mehrere Dateinamen als Argumente zu verwenden. Siehe auch stackoverflow.com/questions/11710552/useless-use-of-catWenn ich Ihre Frage richtig verstehe, möchten Sie die Zeilen danach
TERMINATE
, ohne dieTERMINATE
-zeile.awk
kann dies auf einfache Weise tun:Erläuterung:
if(found) print
) gibt also zunächst nichts aus.Dadurch werden alle Zeilen nach der Zeile gedruckt
TERMINATE
.Verallgemeinerung:
Beispiel:
Erläuterung:
found
eingestellt ist.found=1
so ein, dass die folgenden Zeilen gedruckt werden. Beachten Sie, dass diese Überprüfung nach dem eigentlichen Druck durchgeführt wird, um die Startzeile vom Ergebnis auszuschließen .Anmerkungen:
BEGIN{found=0}
am Anfang des awk-Ausdrucks ein hinzufügen können .quelle
{if(found) print}
ist ein bisschen ein Anti-Pattern in awk, es ist idiomatischer, den Block durch nur zu ersetzenfound
oderfound;
wenn Sie danach einen anderen Filter benötigen.awk '{if(found) print} /TERMINATE/{found=1}' your_file
mitawk 'found; /TERMINATE/{found=1}' your_file
, sollten sie beide das gleiche tun.Verwenden Sie die Bash-Parametererweiterung wie folgt:
quelle
printf
oder sicherstellen, dass Sie genau wissen, an was Sie übergebenecho
.).grep -A 10000000 'TERMINATE'-Datei
quelle
Es gibt viele Möglichkeiten, dies zu tun mit
sed
oderawk
:Dies sucht
TERMINATE
in Ihrer Datei und druckt von dieser Zeile bis zum Ende der Datei.Dies ist genau das gleiche Verhalten wie
sed
.Wenn Sie die Nummer der Zeile kennen, von der aus Sie mit dem Drucken beginnen möchten, können Sie diese zusammen mit
NR
(Nummer des Datensatzes, der schließlich die Nummer der Zeile angibt) angeben:Beispiel
quelle
more +7 file
Wenn Sie aus irgendeinem Grund die Verwendung von sed vermeiden möchten, wird die Zeilenübereinstimmung
TERMINATE
bis zum Ende der Datei wie folgt gedruckt :und das Folgende wird von der folgenden Zeilenübereinstimmung
TERMINATE
bis zum Ende der Datei gedruckt :Es sind zwei Prozesse erforderlich, um das zu tun, was sed in einem Prozess tun kann. Wenn sich die Datei zwischen der Ausführung von grep und tail ändert, kann das Ergebnis inkohärent sein. Daher empfehle ich die Verwendung von sed. Wenn die Datei nicht enthält
TERMINATE
, schlägt der 1. Befehl fehl.quelle
Alternativen zur hervorragenden
sed
Antwort von jfgagne, die keine passende Zeile enthalten:awk '/TERMINATE/ {y=1;next} y'
( https://stackoverflow.com/a/18166628 )awk '/TERMINATE/ ? c++ : c'
( https://stackoverflow.com/a/23984891 )perl -ne 'print unless 1 .. /TERMINATE/'
( https://stackoverflow.com/a/18167194 )quelle
Dies könnte eine Möglichkeit sein, dies zu tun. Wenn Sie wissen, in welcher Zeile der Datei Sie Ihr Grep-Wort haben und wie viele Zeilen Sie in Ihrer Datei haben:
grep -A466 'TERMINATE'-Datei
quelle
grep
ist sie nicht einmal erforderlich. Sie können nur verwendentail -n $NUM
, so ist dies nicht wirklich eine Antwort.sed ist ein viel besseres Werkzeug für den Job: sed -n '/ re /, $ p' Datei
wo re ist regexp.
Eine weitere Option ist das Flag --after-context von grep. Sie müssen eine Zahl eingeben, um mit zu enden. Wenn Sie wc für die Datei verwenden, sollte dies den richtigen Wert für den Stopp angeben. Kombinieren Sie dies mit -n und Ihrem Übereinstimmungsausdruck.
quelle
Diese drucken alle Zeilen von der zuletzt gefundenen Zeile "TERMINATE" bis zum Ende der Datei:
quelle
grep
damit Sie sie füttern können,tail
ist ein verschwenderisches Antimuster. Das Finden der Übereinstimmung und das Drucken bis zum Ende der Datei (oder umgekehrt das Drucken und Stoppen bei der ersten Übereinstimmung) erfolgt hervorragend mit den normalen, wesentlichen Regex-Werkzeugen selbst. Das Massivegrep | tail | sed | awk
ist auch an und für sich ein massiver nutzloser Gebrauch vongrep
und Freunden .tail
Sie die Aufgabe los und erledigen Sie sie insgesamt in dem leistungsfähigeren Werkzeug. Auf jeden Fall steht auf dem Titel eindeutig "erstes Spiel".