2016-04-29 5 views

Antwort

1

Grep ist hierfür nicht geeignet, da sie in erster Linie für die Filterung bestimmte Zeilen, aber Sie fragen über die Beziehungen zwischen verschiedenen Linien. Grep kann gezwungen werden, einige Dinge über mehrere Zeilen hinweg durch (ab) mit der -z Flag, die Nullbyte getrennte Zeilen erwartet, aber es ist in der Regel nicht schön.

Awk ermöglicht eine einfache Lösung:

$ awk 'BEGIN{RS="TAGDESCRIPTIONS"}/foo/{print $1}' infile 
bar 

Hier wird die Datensatztrennzeichen RS zu TAGDESCRIPTIONS, so wird die Eingabe als drei Datensätze (\n steht für eine neue Zeile) interpretiert:

<empty record> 
example\nTAGS   tmp\nTAGS   line\n 
bar\nTAGS   com\nTAGS   foo\n 

Die erste ist leer, da die Datei mit einem Datensatztrennzeichen beginnt.

Für jeden Datensatz haben wir bis zur ersten Zeilenumbruch die Tag-Beschreibung. Was wir mit

/foo/{print $1} 

sagen ist: Wenn der Datensatz foo entspricht, wobei das erste Feld des Datensatzes drucken (der Beschreibung).

Dies ist überhaupt nicht bombensicher. Wenn die Beschreibung aus mehreren Wörtern besteht, wird nur die erste ausgegeben. Wenn die Beschreibung anstelle des Tags übereinstimmt, handelt es sich um ein falsches positives Ergebnis. Wenn der Datensatz foobar, aber nicht bar enthält, wird er dennoch übereinstimmen.

Diese Eingabe Beispiel würde die einfache Lösung abwerfen:

TAGDESCRIPTIONS foo 
TAGS   blah 
TAGDESCRIPTIONS example 
TAGS   tmp 
TAGS   line 
TAGS   foobar 
TAGS   barfoo 
TAGDESCRIPTIONS bar and more words 
TAGS   com 
TAGS   foo 

Es ist ein Tag Beschreibung mit foo, Tags enthältfoo und eine Tag-Beschreibung aus mehreren Wörtern bestehen.

Wir alle, dass bei Zeilenumbrüche durch Aufspalten der Aufzeichnungen beheben können, dann jedes Element außer der Beschreibung zum Suchbegriff Vergleich:

awk ' 
BEGIN { RS = "TAGDESCRIPTIONS *" } 

{ 
    # Split record at newlines, store in arr 
    split($0, arr, "\n") 

    # Skip first element (description), compare to 'foo' 
    for (i = 2; i <= length(arr); ++i) { 
     if (arr[i] ~ " +foo$") { 

      # Matches - print description 
      print arr[1] 

      # No need to look at the rest of the record 
      break 
     } 
    } 
}' infile 

was

bar and more words 

GNU awk, um genau zu sein, aufgrund der Multi-Zeichen-Record-Trennzeichen und der length-Funktion.

+1

Sie sollten erwähnen, das ist gawk-spezifisch wegen Multi-Char RS und 'Länge (Array)'. –

0

Ich gebe es eine Chance.
Ich weiß nicht grep oder awk, aber die unten ist nur eine rohe Regex
, die PCRE-Stil Lookahead und eine Inline-Modifikatorgruppe verwendet.

(?ms)^TAGDESCRIPTIONS\s+(\w*)\s+(?:(?!^TAGDESCRIPTIONS).)+^TAGS\s+foo

Expanded
(?ms) 
^ TAGDESCRIPTIONS \s+ 
(\w*)      # (1) 
\s+ 
(?: 
     (?!^TAGDESCRIPTIONS) 
     . 
)+ 
^ TAGS \s+ foo 

Das bar Wort wird in Capture-Gruppe 1. Fleisch heraus die Regex, wie Sie benötigen.

Ausgabe

** Grp 0 - (pos 68 , len 83) 
TAGDESCRIPTIONS bar 
TAGS   com      
TAGS   foo 
** Grp 1 - (pos 84 , len 3) 
bar 
2
$ awk '/TAGDESCRIPTIONS/{d=$2} /foo/{print d}' file 
bar 
Verwandte Themen