2012-10-30 12 views
5

Próbuję użyć awk do analizy wyrażenia wielowierszowego. Jeden z nich wygląda następująco:Dopasowywanie awk i multilines (subregex)

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

Potrzebuję wyodrębnić wartość skojarzoną z _begin i _attrib1. W tym przykładzie powinien powrócić skrypt awk (po jednym w wierszu):

hello world ! super duper yet another value 

Używany separator to znak tabulacji (\ t). Spacje są używane tylko w ciągu znaków.

Odpowiedz

8

Poniższy skrypt awk spełnia swoje zadanie:

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

nie określono, czy chcesz zakładka (\t) być twoim wyjście separatora pola. Jeśli tak, daj mi znać, a zaktualizuję odpowiedź. (Albo może, jest to trywialne.)

Oczywiście, jeśli chcesz straszny alternatywą (ponieważ jesteśmy coraz bliżej do Halloween), oto rozwiązanie używając 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 

Jak ta praca? Mwaahahaa, cieszę się, że pytasz.

  • /^_begin./{s///;h;}; - Kiedy widzimy _begin, rozebrać go i przechowywać resztę linii sed na „trzymaj bufor”.
  • - Po zobaczeniu _attrib1, usuń go, dołącz do bufora podtrzymującego, zamień bufor wstrzymania i obszar wzorkowy, zamień znaki nowej przestrzeni na spacje i ponownie umieść bufor wstrzymania i obszar wzorów.
  • /^_end/{;g;p;} - Doszliśmy do końca, więc pociągnij bufor podtrzymujący do przestrzeni wzorów i wydrukuj.

Zakłada się, że separator pól wejściowych to tylko jedna zakładka.

TO proste. Kto powiedział, że sed był tajemniczy ?!

+0

_attrib11 czyni ten skrypt nie powiedzie się (_attrib1 mecze) – malat

+0

Nie było '_attrib11' w przykładowych danych podałeś. Jeśli chcesz, możesz ustawić warunki takie jak '$ 1 ==" _ attrib1 "' zamiast '/^_ attrib1 /' do obsługi tego, lub możesz po prostu zostawić to jako wyrażenie regularne, ale je zakończyć, np. '$ 1 ~/^ _ attrib1 $/'. Polecam pierwsze alternatywne rozwiązanie; zawsze wybieraj ciąg dopasowany pierwszy, regex (przynajmniej) drugi. – ghoti

+0

Zaktualizowałem moją odpowiedź na nowe wymaganie. Dodano również opcję "sed" dla przyjemności z czytania. – ghoti

1

To powinno działać:

#!/bin/bash 

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