it-swarm.com.de

Wie bekomme ich den Teil der Datei nach der Zeile, die dem grep-Ausdruck entspricht? (erstes Spiel)

Ich habe eine Datei mit etwa 1000 Zeilen. Ich möchte, dass der Teil meiner Datei hinter der Zeile steht, die meiner grep-Anweisung entspricht.

d.h.

$ cat file | grep 'TERMINATE'     // Its found on line 534

Also möchte ich die Datei aus Zeile 535 to line 1000 zur weiteren Verarbeitung.

Wie mache ich es ?

142
Yugal Jindle

Folgendes druckt die Zeile, die mit TERMINATE bis zum Ende der Datei übereinstimmt:

sed -n -e '/TERMINATE/,$p'

Erklärt: -n deaktiviert das Standardverhalten von sed des Druckens jeder Zeile nach Ausführung des Skripts. -e hat ein Skript für sed angegeben. /TERMINATE/,$ ist eine Adressbereichswahl, die die erste Zeile angibt, die dem regulären Ausdruck TERMINATE entspricht (wie grep) bis zum Ende der Datei ($) und p ist der Druckbefehl, der die aktuelle Zeile druckt.

Dies wird von der Zeile gedruckt, die auf die Zeile folgt, die mit TERMINATE bis zum Ende der Datei übereinstimmt:
(von NACH der übereinstimmenden Zeile zu EOF, NICHT einschließlich der übereinstimmenden Zeile)

sed -e '1,/TERMINATE/d'

Erklärt: 1,/TERMINATE/ ist eine Adressbereichsauswahl (Zeile), die die erste Zeile für die Eingabe in die erste Zeile angibt, die dem regulären Ausdruck TERMINATE entspricht, und d ist der Löschbefehl, der die aktuelle Zeile löscht und zur nächsten Zeile springt. Da sed das Standardverhalten beim Drucken der Zeilen ist, werden die Zeilen nach TERMINATE bis zum Ende der Eingabe gedruckt.

Bearbeiten:

Wenn Sie die Zeilen vor TERMINATE haben wollen:

sed -e '/TERMINATE/,$d'

Und wenn Sie beide Zeilen vor und nach TERMINATE in 2 verschiedenen Dateien in einem einzigen Durchgang haben möchten:

sed -e '1,/TERMINATE/w before
/TERMINATE/,$w after' file

Die Vorher- und Nachher-Dateien enthalten die Zeile mit terminate. Um sie zu verarbeiten, benötigen Sie:

head -n -1 before
tail -n +2 after

Edit2:

WENN Sie die Dateinamen im sed-Skript nicht hartcodieren möchten, können Sie:

before=before.txt
after=after.txt
sed -e "1,/TERMINATE/w $before
/TERMINATE/,\$w $after" file

Dann müssen Sie jedoch den Code $ für die letzte Zeile kennzeichnen, damit die Shell nicht versucht, die Variable $w zu erweitern (beachten Sie, dass wir jetzt das Skript anstelle von einfachen Anführungszeichen in doppelte Anführungszeichen setzen).

Ich habe vergessen zu sagen, dass die neue Zeile nach den Dateinamen im Skript wichtig ist, damit sed weiß, dass die Dateinamen enden.


Edit: 2016-0530

Sébastien Clément fragte: "Wie würden Sie die hartcodierte Variable TERMINATE durch eine Variable ersetzen?"

Sie würden eine Variable für den übereinstimmenden Text erstellen und dann wie im vorherigen Beispiel machen: 

matchtext=TERMINATE
before=before.txt
after=after.txt
sed -e "1,/$matchtext/w $before
/$matchtext/,\$w $after" file

so verwenden Sie eine Variable für den übereinstimmenden Text in den vorherigen Beispielen:

## Print the line containing the matching text, till the end of the file:
## (from the matching line to EOF, including the matching line)
matchtext=TERMINATE
sed -n -e "/$matchtext/,\$p"
## Print from the line that follows the line containing the 
## matching text, till the end of the file:
## (from AFTER the matching line to EOF, NOT including the matching line)
matchtext=TERMINATE
sed -e "1,/$matchtext/d"
## Print all the lines before the line containing the matching text:
## (from line-1 to BEFORE the matching line, NOT including the matching line)
matchtext=TERMINATE
sed -e "/$matchtext/,\$d"

Die wichtigsten Punkte zum Ersetzen von Text durch Variablen in diesen Fällen sind: 

  1. Variablen ($variablename), die in single quotes ['] eingeschlossen sind, werden nicht "erweitert", aber Variablen in double quotes ["] werden es. Sie müssen also alle single quotes in double quotes ändern, wenn sie Text enthalten, den Sie durch eine Variable ersetzen möchten. 
  2. Die sed-Bereiche enthalten auch einen $ und werden unmittelbar gefolgt von einem Buchstaben wie: $p, $d, $w. Sie sehen auch aus wie Variablen, die erweitert werden sollen. Daher müssen Sie diese $-Zeichen mit einem umgekehrten Schrägstrich [\] wie folgt ausdrücken: \$p, \$d, \$w.
263
jfg956

Als einfache Annäherung könnten Sie verwenden

grep -A100000 TERMINATE file

was für TERMINATE greift und bis zu 100000 Zeilen nach dieser Zeile ausgibt.

Von der Manpage

-A NUM, --after-context=NUM

NUM-Zeilen mit nachfolgendem Kontext nach übereinstimmenden Zeilen drucken. Platziert eine Zeile mit einem Gruppentrennzeichen (-) zwischen benachbarte Gruppen von Spielen. Mit -o oder --only passend Option hat dies keine Auswirkung und es wird eine Warnung ausgegeben.

59
aioobe

Ein Werkzeug, das Sie hier verwenden können, ist awk:

cat file | awk 'BEGIN{ found=0} /TERMINATE/{found=1}  {if (found) print }'

Wie funktioniert das:

  1. Wir setzen die Variable 'found' auf Null und bewerten False
  2. wenn mit dem regulären Ausdruck eine Übereinstimmung für 'TERMINATE' gefunden wird, setzen wir sie auf eins.
  3. Wenn unsere gefundene Variable als True ausgewertet wird, drucken Sie :)

Die anderen Lösungen benötigen möglicherweise viel Speicher, wenn Sie sie für sehr große Dateien verwenden.

25
Jos De Graeve

Verwenden Sie die Bash-Parametererweiterung wie folgt:

content=$(cat file)
echo "${content#*TERMINATE}"
7
Mu Qiao

Wenn ich Ihre Frage richtig verstehe, möchten Sie die Zeilen afterTERMINATE und nicht die TERMINATE- Zeile. awk kann dies auf einfache Weise tun:

awk '{if(found) print} /TERMINATE/{found=1}' your_file

Erläuterung:

  1. Obwohl dies keine bewährte Methode ist, können Sie sich darauf verlassen, dass alle Variablen standardmäßig 0 oder die leere Zeichenfolge verwenden, wenn sie nicht definiert ist. Der erste Ausdruck (if(found) print) druckt also nichts, um damit zu beginnen.
  2. Nachdem der Druck abgeschlossen ist, prüfen wir, ob dies die Startlinie ist (die nicht enthalten sein sollte).

Dadurch werden alle Zeilen after der TERMINATE-Zeile gedruckt.


Verallgemeinerung:

  • Sie haben eine Datei mit Start- und Ende- Zeilen und möchten, dass die Zeilen zwischen diesen Zeilen ausgenommen die Start- und Ende- Zeilen.
  • Start- und Ende- Zeilen können durch einen regulären Ausdruck definiert werden, der der Zeile entspricht.

Beispiel:

$ cat ex_file.txt 
not this line
second line
START
A good line to include
And this line
Yep
END
Nope more
...
never ever
$ awk '/END/{found=0} {if(found) print} /START/{found=1}' ex_file.txt 
A good line to include
And this line
Yep
$

Erläuterung:

  1. Wenn die end-Zeile gefunden wird, sollte nicht gedruckt werden. Beachten Sie, dass diese Prüfung vorher der eigentliche Druck ausgeführt wird, um die Ende- Zeile vom Ergebnis auszuschließen.
  2. Drucken Sie die aktuelle Zeile, wenn found eingestellt ist.
  3. Wenn die Start-Zeile gefunden wird, setzen Sie found=1 so, dass die folgenden Zeilen gedruckt werden. Beachten Sie, dass diese Prüfung after des eigentlichen Drucks ausgeführt wird, um die Start- Zeile vom Ergebnis auszuschließen.

Anmerkungen:

  • Der Code basiert auf der Tatsache, dass alle awk-vars standardmäßig 0 oder die leere Zeichenfolge verwenden, wenn sie nicht definiert ist. Dies ist gültig, ist jedoch möglicherweise nicht die bewährte Methode, sodass Sie am Anfang des awk-Ausdrucks einen BEGIN{found=0} hinzufügen können.
  • Wenn mehrere Anfang-Ende- Blöcke gefunden werden, werden sie alle gedruckt.
7
UlfR

Wenn Sie aus irgendeinem Grund die Verwendung von sed vermeiden möchten, wird die Zeile mit TERMINATE bis zum Ende der Datei gedruckt:

tail -n "+$(grep -n 'TERMINATE' file | head -n 1 | cut -d ":" -f 1)" file

und Folgendes wird von der folgenden Zeile bis zum Ende der Datei mit TERMINATE gedruckt:

tail -n "+$(($(grep -n 'TERMINATE' file | head -n 1 | cut -d ":" -f 1)+1))" file

Sed benötigt zwei Prozesse, und wenn sich die Datei zwischen Ausführung von grep und tail ändert, kann das Ergebnis inkohärent sein. Wenn die Datei keine TERMINATE enthält, schlägt der 1. Befehl fehl.

3
jfg956

Es gibt viele Möglichkeiten, dies mit sed oder awk zu tun:

sed -n '/TERMINATE/,$p' file

Dies sucht nach TERMINATE in Ihrer Datei und druckt von dieser Zeile bis zum Ende der Datei.

awk '/TERMINATE/,0' file

Dies ist genau das gleiche Verhalten wie sed.

Wenn Sie die Nummer der Zeile kennen, von der aus Sie den Druck starten möchten, können Sie sie zusammen mit NR angeben (Nummer des Datensatzes, die schließlich die Nummer der Zeile angibt):

awk 'NR>=535' file

Beispiel

$ seq 10 > a        #generate a file with one number per line, from 1 to 10
$ sed -n '/7/,$p' a
7
8
9
10
$ awk '/7/,0' a
7
8
9
10
$ awk 'NR>=7' a
7
8
9
10
2
fedorqui

grep -A 10000000 'TERMINATE' Datei 

  • ist viel, viel schneller als sed, vor allem bei wirklich großen Dateien. Es funktioniert bis zu 10 Millionen Zeilen (oder was auch immer Sie einlegen), es ist also kein Schaden, wenn Sie dies groß genug machen, um mit allem, was Sie treffen, fertig zu werden.
1
user8910163

Dies könnte eine Möglichkeit sein. Wenn Sie wissen, welche Zeile der Datei Ihr grep-Word enthält und wie viele Zeilen Sie in Ihrer Datei haben:

grep -A466 'TERMINATE'-Datei

0
Mariah

Alternativen zur exzellenten sed-Antwort von jfgagne, die keine passende Zeile enthält:

0
mivk