2013-08-19 18 views
5

Cześć Szukam awk, który może znaleźć dwa wzory i wydrukować dane między nimi do plik tylko wtedy, gdy w środku znajduje się trzeci wzór w środku. na przykład:Awk między dwoma wzorami ze wzorem w środku

Start 
1 
2 
middle 
3 
End 
Start 
1 
2 
End 

And the output will be: 
Start 
1 
2 
middle 
3 
End 

znalazłem w sieci awk/patterns1 /,/patterns2/'path> text.txt ale muszę tylko wyjście z wzorców trzecich w środku.

+0

Fiddly, ale wykonalne. Będziesz musiał zapisać materiał pomiędzy początkiem i końcem, a kiedy natkniesz się na Środek, zwróć uwagę, że zapisany materiał powinien zostać wydrukowany, a podczas przetwarzania Koniec sprawdź, czy zapisany materiał powinien zostać wydrukowany. Nie mam czasu, aby to zmniejszyć, by teraz kodować. (Zapisz każde '0 $' w tablicy po rozpoznaniu polecenia Start, zatrzymaj zapisywanie na Koniec, wydrukuj tablicę, jeśli jest to konieczne, i usuń tablicę bez względu na to). –

+0

Czy też mogą istnieć dowolne linie danych nie pomiędzy początkiem i końcem? Czy jest to zawsze ciąg linii Start..End, ale tylko niektóre z nich muszą zostać wydrukowane. –

+0

może być pusty, ale jest tylko pusty o środkowym wzorze –

Odpowiedz

2

Ten awk powinno działać:

awk '$1=="Start"{ok++} ok>0{a[b++]=$0} $1=="middle"{ok++} $1=="End"{if(ok>1) for(i=0; i<length(a); i++) print a[i]; ok=0;b=0;delete a}' file 

Start 
1 
2 
middle 
3 
End 

Expanded:

awk '$1 == "Start" { 
    ok++ 
} 
ok > 0 { 
    a[b++] = $0 
} 
$1 == "middle" { 
    ok++ 
} 
$1 == "End" { 
    if (ok > 1) 
     for (i=0; i<length(a); i++) 
     print a[i]; 
    ok=0; 
    b=0; 
    delete a 
}' file 
3

Wystarczy użyć jakieś flagi z awk:

/Start/ { 
    start_flag=1 
} 

/middle/ { 
    mid_flag=1 
} 

start_flag { 
    n=NR; 
    lines[NR]=$0 
} 

/End/ { 
    if (start_flag && mid_flag) 
     for(i=n;i<NR;i++) 
      print lines[i] 
    start_flag=mid_flag=0 
    delete lines 
} 
3

I tu jest rozwiązanie bez flagi:

$ awk 'BEGIN{RS="End"}/middle/{printf "%s", $0; print RT}' file 
Start 
1 
2 
middle 
3 
End 

Objaśnienie: Zmienna RS jest separator rekord, więc możemy ustawić go na „End”, tak, że każdy rekord jest oddzielony przez „End”.

Następnie filtrować rekordy, które zawierają „Middle” z filtrem /middle/, a dla dopasowanych rekordów możemy wydrukować bieżący rekord $0 i separator z print RT

+0

Interesujące ... ale myślę, że to uzasadnia pewne wyjaśnienie, jak to działa. –

+1

Nie bierze pod uwagę 'Start' po prostu drukuje rekordy zawierające' middle' i 'End'. Dodajesz również dodatkowy znak nowej linii po zapisie. –

+0

@ JonathanLeffler dodał wyjaśnienie – user000001

3

zmodyfikował user000001 awk

awk '/middle/{printf "%s%s\n",$0,RT}' RS="End" file 

EDIT: testy Dodane przez znacznik początkowy

awk '/Start/ && /middle/{printf "%s%s\n",$0,RT}' RS="End" file 
+0

Nie sprawdza to opcji "Rozpocznij" – mschilli

+0

Zaktualizowałem mój wpis, aby przetestować dla opcji "Rozpocznij" – Jotne

2

To będzie Wor k z każdej nowoczesnej awk:

awk '/Start/{f=1;rec=""} f{rec=rec $0 ORS} /End/{if (rec~/middle/) printf "%s",rec}' file 

rozwiązań, które określone RS na „Koniec” są specyficzne dla gawk, który może być w porządku, ale na pewno warto wspomnieć.