@Ed Morton:Ich stimme dir hier nicht zu. Ich habe sed
gefunden sehr nützlich und einfach (sobald Sie das Konzept der Muster- und Haltepuffer verstanden haben), um einen eleganten Weg für mehrzeiliges Grepping zu finden.
Nehmen wir zum Beispiel eine Textdatei, die Hostnamen und einige Informationen über jeden Host enthält, mit viel Müll dazwischen, der mir egal ist.
Host: foo1
some junk, doesnt matter
some junk, doesnt matter
Info: about foo1 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Info: a second line about foo1 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Host: foo2
some junk, doesnt matter
Info: about foo2 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Für mich ein awk-Skript, um nur die Zeilen mit dem Hostnamen und dem entsprechenden info
zu erhalten Zeile würde etwas mehr dauern, als ich mit sed machen kann:
sed -n '/Host:/{h}; /Info/{x;p;x;p;}' myfile.txt
Ausgabe sieht so aus:
Host: foo1
Info: about foo1 that I really care about!!
Host: foo1
Info: a second line about foo1 that I really care about!!
Host: foo2
Info: about foo2 that I really care about!!
(Beachten Sie, dass Host: foo1
erscheint zweimal in der Ausgabe.)
Erklärung:
-n
deaktiviert die Ausgabe, sofern nicht explizit gedruckt- erste Übereinstimmung, findet und fügt den
Host:
ein Zeile in Haltepuffer (h) - zweite Übereinstimmung, findet die nächste Info:-Zeile, tauscht aber zuerst (x) die aktuelle Zeile im Musterpuffer mit dem Haltepuffer aus und gibt (p) den
Host:
aus Zeile, tauscht dann (x) und druckt (p) die Info:-Zeile.
Ja, dies ist ein vereinfachtes Beispiel, aber ich vermute, dass dies ein häufiges Problem ist, das schnell mit einem einfachen Sed-Einzeiler behandelt wurde. Für wesentlich komplexere Aufgaben, beispielsweise solche, bei denen Sie sich nicht auf eine vorgegebene, vorhersehbare Reihenfolge verlassen können, ist awk möglicherweise besser geeignet.
Wenn sed eine Datei zeilenweise liest, wird die gerade gelesene Zeile in das Muster eingefügt Puffer (Musterraum). Der Musterpuffer ist wie der temporäre Puffer, der Notizblock, in dem die aktuellen Informationen gespeichert werden. Wenn Sie sed sagen, dass es drucken soll, druckt es den Musterpuffer.
Hold Buffer / Hold Space ist wie ein Langzeitspeicher, so dass Sie etwas abfangen, speichern und später wiederverwenden können, wenn sed eine andere Zeile verarbeitet. Sie verarbeiten den Haltebereich nicht direkt, sondern müssen ihn kopieren oder an den Musterbereich anhängen, wenn Sie etwas damit machen möchten. Zum Beispiel der Druckbefehl p
druckt nur den Musterbereich. Ebenso s
arbeitet auf dem Musterraum.
Hier ist ein Beispiel:
sed -n '1!G;h;$p'
(Die Option -n unterdrückt das automatische Drucken von Zeilen)
Hier gibt es drei Befehle:1!G
, h
und $p
. 1!G
hat eine Adresse, 1
(erste Zeile), sondern die !
bedeutet, dass der Befehl außer überall ausgeführt wird auf der ersten Zeile. $p
hingegen wird nur in der letzten Zeile ausgeführt. Was also passiert, ist Folgendes:
- erste Zeile wird gelesen und automatisch in den Musterbereich eingefügt
- in der ersten Zeile wird der erste Befehl nicht ausgeführt;
h
kopiert die erste Zeile in den hold Leerzeichen. - jetzt ersetzt die zweite Zeile alles, was im Musterbereich war
- In der zweiten Zeile führen wir zuerst
G
aus , wobei der Inhalt des Haltepuffers an den Musterpuffer angehängt und durch einen Zeilenumbruch getrennt wird. Der Musterbereich enthält jetzt die zweite Zeile, einen Zeilenumbruch und die erste Zeile. - Dann
h
Der Befehl fügt den verketteten Inhalt des Musterpuffers in den Haltebereich ein, der nun die umgekehrten Zeilen zwei und eins enthält. - Wir fahren mit Zeile Nummer drei fort – gehen Sie zu Punkt (3) oben.
Schließlich, nachdem die letzte Zeile gelesen wurde und der Haltebereich (der alle vorherigen Zeilen in umgekehrter Reihenfolge enthält) an den Musterbereich angehängt wurde, wird der Musterbereich mit p
gedruckt . Wie Sie erraten haben, macht das obige genau das, was tac
Befehl tut -- druckt die Datei in umgekehrter Reihenfolge.
Obwohl die Antwort von @January und das Beispiel nett sind, war die Erklärung für mich nicht genug. Ich musste viel suchen und lernen, bis ich verstanden habe, wie genau sed -n '1!G;h;$p'
funktioniert. Daher möchte ich den Befehl für jemanden wie mich näher erläutern.
Lassen Sie uns zunächst sehen, was der Befehl tut.
$ echo {a..d} | tr ' ' '\n' # Prints from 'a' to 'd' in each line
a
b
c
d
$ echo {a..d} | tr ' ' '\n' | sed -n '1!G;h;$p'
d
c
b
a
Es kehrt die Eingabe um wie tac
Befehl tut.
sed
liest Zeile für Zeile, sehen wir uns also an, was auf dem Musterplatz passiert und das Halte-Leerzeichen an jeder Zeile. Als h
Der Befehl kopiert den Inhalt des Musterbereichs in den Haltebereich, beide Bereiche haben denselben Text.
Read line Pattern Space / Hold Space Command executed
-----------------------------------------------------------
a a$ h
b b\na$ 1!G;h
c c\nb\na$ 1!G;h
d d\nc\nb\na$ 1!G;h;$p
In der letzten Zeile $p
gibt d\nc\nb\na$
aus die formatiert ist zu
d
c
b
a
Wenn Sie den Musterraum für jede Zeile sehen möchten, können Sie einen l
hinzufügen Befehl.
$ echo {a..d} | tr ' ' '\n' | sed -n '1!G;h;l;$p'
a$
b\na$
c\nb\na$
d\nc\nb\na$
d
c
b
a
Ich fand es sehr hilfreich, dieses Video-Tutorial anzuschauen. Verstehen, wie sed funktioniert, da der Typ Schritt für Schritt zeigt, wie jeder Raum verwendet wird. Der Halteabstand wird im 4. Tutorial erwähnt, aber ich empfehle, sich alle Videos anzusehen, wenn Sie mit sed
nicht vertraut sind .
Auch das Sed-Dokument von GNU und das Sed-Tutorial von Bruce Barnett sind sehr gute Referenzen.