2012-10-30 11 views
5

Ich versuche, awk zu verwenden, um einen Multiline-Ausdruck zu analysieren. Eine einzige von ihnen sieht so aus:Awk und Multilinien-Abgleich (Sub-Regex)

_begin hello world ! 
_attrib0 123 
_attrib1 super duper 
_attrib1 yet another value 
_attrib2 foo 
_end 

Ich muss den Wert für _begin und _attrib1 extrahieren. So im Beispiel sollte die awk-Skript zurückgeben (eine pro Zeile):

hello world ! super duper yet another value 

Der Separator verwendet wird, ein Register (\ t) Zeichen. Leerzeichen werden nur innerhalb von Zeichenfolgen verwendet.

Antwort

8

Die folgende awk-Skript hat den Zweck erfüllt:

#!/usr/bin/awk -f 
BEGIN { FS="\t"; } 
/^_begin/  { output=$2; } 
$1=="_attrib1" { output=output " " $2; } 
/^_end/  { print output; } 

Sie nicht angeben, ob Sie eine Registerkarte (\t) möchten Ihre Ausgabe Feldtrenn sein. Wenn Sie dies tun, lassen Sie es mich wissen und ich werde die Antwort aktualisieren. (Sie können auch, es ist trivial.)

Natürlich, wenn Sie eine beängstigende Alternative wollen (da wir immer nah an Hallowe'en), hier eine Lösung mit sed:

$ sed -ne '/^_begin./{s///;h;};/^_attrib1[^0-9]/{s///;H;x;s/\n/ /;x;};/^_end/{;g;p;}' input.txt 
hello world ! super duper yet another value 

Wie funktioniert diese Arbeit? Mwaahahaa, ich bin froh, dass du gefragt hast.

  • /^_begin./{s///;h;}; - Wenn wir _begin sehen, es abzustreifen und speichern den Rest der Zeile zu sed die „halten Puffer“.
  • /^_attrib1[^0-9]/{s///;H;x;s/\n/ /;x;}; - Wenn wir _attrib1 sehen, ziehen Sie es ab, hängen es an den Haltepuffer, tauschen den Haltepuffer und den Musterbereich, ersetzen Zeilenumbrüche durch Leerzeichen und tauschen den Haltepuffer und den Musterbereich wieder aus.
  • /^_end/{;g;p;} - Wir haben das Ende erreicht, also ziehen Sie den Haltepuffer in den Musterbereich und drucken Sie ihn aus.

Dies setzt voraus, dass Ihr Eingabefeld Trennzeichen nur eine einzelne Registerkarte ist.

SO einfach. Wer hat jemals gesagt sed war geheimnisvoll ?!

+0

_attrib11 wird dieses Skript macht Daten fehlschlägt (_attrib1 Spiele) – malat

+0

Es gab keine '_attrib11' in den Proben Sie zur Verfügung gestellt. Wenn Sie möchten, können Sie Bedingungen wie '$ 1 ==" _ attrib1 "' anstelle von '/^_ attrib1 /' erstellen, um das zu handhaben, oder Sie können es einfach als Regex belassen, aber beenden Sie es, wie '$ 1 ~/^ _ attrib1 $/'. Ich empfehle die erste alternative Lösung; Wählen Sie immer zuerst String-Matching, Regex (mindestens) Second. – ghoti

+0

Aktualisierte meine Antwort für Ihre neue Anforderung. Auch eine 'sed' Alternative hinzugefügt, für Ihr Lesevergnügen. – ghoti

1

sollte diese Arbeit:

#!/bin/bash 

awk 'BEGIN {FS="\t"} {if ($1=="_begin" || $1=="_attrib1") { output=output " " $2 }} END{print output}'