2017-02-20 6 views
1

Ich habe eine mehrzeilige Ausgabe wie folgt aus:Parse mehrzeilige mit awk

foo: some text 
    goes here 
    and here 
    and here 
bar: more text 
    goes here 
    and here 
xyz: and more... 
    and more... 
    and more... 

Die Formattext genau ist, wie hier gezeigt. Die "Gruppen/Abschnitte" des Textes, an denen ich interessiert bin, beginnen gleich nach dem Anfang der Zeile und enden bei der Zeile vor dem nächsten Text, beginnen direkt am Anfang einer Zeile.

In diesem Beispiel wären die Gruppen foo und der gesamte Text kurz vor bar. Dann bar und der gesamte Text kurz vor xyz. Und schließlich, xyz bis zum Ende.

+4

nicht beschreiben, wie die Ausgabe aussehen soll, zeigen Sie es im Codeblock. – Kent

+2

Und irgendeine Art von Versuch wäre nett. – grail

+0

Es ist ziemlich schwierig, das Problem ohne erwartete Ausgabe zu verstehen – anubhava

Antwort

2

Eingang

$ cat file 
foo: some text 
    goes here 
    and here 
    and here 
bar: more text 
    goes here 
    and here 
xyz: and more... 
    and more... 
    and more... 

Ausgabe

$ awk '/:/{f=/^foo/}f' file 
foo: some text 
    goes here 
    and here 
    and here 

Incase, wenn Sie Linie dann abgestimmt überspringen wollen

$ awk '/:/{f=/^foo/;next}f' file 
    goes here 
    and here 
    and here 

Oder sogar

# Just modify variable search value 
# 1st approach 
$ awk -v search="foo" '/:/{f=$0~"^"search}f' file 
foo: some text 
    goes here 
    and here 
    and here 

# 2nd approach 
$ awk -v search="foo" '/:/{f=$0~"^"search;next}f' file 
    goes here 
    and here 
    and here 
+1

Auch wäre gut, wenn Sie vorschlagen können, 'foo' als eine Variable aus' -v' zu übergeben, so dass er es entsprechend verwenden kann. – Inian

+0

@Inian: sicher werde ich jetzt bearbeiten –

0

Wenn ich Ihre Frage richtig bin zu interpretieren möchten Sie einfach die Leerzeichen entfernen und setzen foo auf einer anderen Leitung als der Teil nach :. Das awk-Skript würde das tun:

awk 'BEGIN{RS="[:\n]"}{$1=$1}1' file 

Ausgang:

foo 
some text 
goes here 
and here 
and here 
bar 
more text 
goes here 
and here 
xyz 
and more... 
and more... 
and more... 

Erläuterung:

  • RS="[:\n] sagt, dass Leitungen entweder an : oder bei \n
  • $1=$1 aufarbeitet die aufgespalten werden Zeile in $0 (entfernt Leerzeichen zu Beginn von Linie)
  • 1 sagt, dass jede Zeile mit der „Standardaktion“ Prozesse sein sollte, die print $0
0

ist Wie andere gesagt haben, Sie haben nicht angegeben, was Sie mit den Daten tun wollen, sobald Sie haben analysierte es.

Wenn Sie nur einen bestimmten Brocken extrahieren möchten, sollte die Antwort von Akshay Hegde gut funktionieren.

Wenn Sie jeden Datensatz mit etwas mehr awk-Funktionalität verarbeiten möchten, z. B. die Ausgabe in irgendeiner Weise transformieren (z. B. Verbinden der Zeilen usw.), benötigen Sie wahrscheinlich etwas anderes.

Es gibt ein paar ziemlich einfache Möglichkeiten, die Sie tun können, aber ich denke, der beste Ansatz ist wahrscheinlich, das Datensatztrennzeichen zu ändern.

Die Möglichkeit, einen regulären Ausdruck als Datensatztrennzeichen zu verwenden, ist eine gawk-Erweiterung, aber Sie verwenden wahrscheinlich gawk, wenn Sie unter Linux sind. Hier

ist der Inhalt eines gaffen Programmdatei „prog.awk“:

function process_group(name, body) { 
    print "Got group with name '" name "'"; 
    print body; 
} 

BEGIN { 
    RS="(\n|^)\\S+:" 
    PREV="" 
} 

{ 
    if (PREV!="") { 
     process_group(gensub(/\n?(\S+):/, "\\1", "", PREV), $0); 
    } 
    PREV=RT 
} 

du

gawk -f prog.awk input.txt 

mit ausführen können Alternativ können Sie das Ganze auf dem gaffen command- setzen Zeile, aber es ist einfacher zu lesen, wenn es schön formatiert ist.

Die Idee ist, dass es jedes Mal, wenn es das Datensatztrennzeichen sieht, den Inhalt seit dem letzten Datensatztrennzeichen oder dem Anfang der Datei gibt. Dies bedeutet, dass beim ersten Anzeigen des Datensatztrennzeichens der untere Block mit dem Datensatztrennzeichen "foo:" und ein leerer Textkörper aufgerufen wird, beim zweiten Anzeigen des Datensatztrennzeichens der Block mit "bar:" und der Inhalt dazwischen aufgerufen wird "foo:" und "bar:" usw.

Dies bedeutet, dass das den einzelnen Blöcken entsprechende Record-Trennzeichen das vorherige und nicht das aktuelle Trennzeichen ist. Dies ist leicht zu handhaben, indem das vorherige Datensatztrennzeichen in der "PREV" -Variable verfolgt wird.

So legt der BEGIN-Block das Datensatztrennzeichen RS fest und initialisiert PREV als leer.

Der Block am Ende wird für jeden von RS begrenzten Datensatz aufgerufen, und noch einmal am Ende der Datei.

Wenn "PREV" nicht leer ist, ruft es die Funktion "process_group" mit den aktuellen Körperdaten und dem vorherigen Datensatzseparator auf (die uninteressanten Bits von PREV auf dem Weg mit gensub entfernen). Anschließend ordnet es das aktuell passende Datensatztrennzeichen (RT) der PREV zur nächsten Verwendung zu.

In "process_group" können Sie jede gewünschte Verarbeitung mit jeder Gruppe durchführen. In diesem Fall drucke ich sie nur aus, aber es sollte einfach zu ändern sein, um zu tun, was immer du willst.