2012-10-23 18 views
8

Jestem nowy w pisaniu skryptów i starałem się nauczyć, jak wyodrębnić dowolny tekst, który istnieje pomiędzy dwoma różnymi wzorami. Jestem jednak nadal nie jest w stanie zorientować się, jak wydobyć tekst pomiędzy dwoma wzorami w następującym scenariuszu:sed/awk - drukowanie tekstu między wzorami rozpiętymi w wielu liniach

Jeśli mam mój plik wejście przeczytać:

Hi I would like 
to print text 
between these 
patterns 

i mój oczekiwany wyjście jest jak:

I would like 
to print text 
between these 

czyli mojego pierwszego wyszukiwania wzór „Hi” i pominąć ten wzór, ale wydrukować wszystko, co istnieje w tej samej linii poniższy wzór dopasowane mój drugi searc. Wzór h to "wzory" i chciałbym całkowicie uniknąć drukowania tej linii lub jakichkolwiek linii poza nią.

Próbowałem następujące:

sed -n '/Hi/,/patterns/p' test.txt 

[Wyjście]

Hi I would like 
to print text 
between these 
patterns 

Następnie próbowałem:

`awk ' /'"Hi"'/ {flag=1;next} /'"pattern"'/{flag=0} flag { print }'` test.txt 

[Wyjście]

to print text 
between these 

Czy ktoś może mi pomóc w określeniu, jak to osiągnąć? góry dzięki

Odpowiedz

6

masz prawo pomysł, mini-stan-maszyna w awk ale trzeba pewne niewielkie modów zgodnie z poniższym zapis:

pax> echo 'Hi I would like 
to print text 
between these 
patterns ' | awk ' 
    /patterns/ { echo = 0 } 
    /Hi/ { gsub("^.*Hi ", "", $0); echo = 1 } 
       { if (echo == 1) { print } }' 

Albo, w formie skompresowanej:

awk '/patterns/{e=0}/Hi /{gsub("^.*Hi ","",$0);e=1}{if(e==1){print}}' 

Wyjście to:

I would like 
to print text 
between these 

zgodnie z życzeniem.

Sposób działania tego działa w następujący sposób. Zmienna echo jest początkowo 0, co oznacza, że ​​nie nastąpi echo.

Każda linia jest sprawdzana po kolei. Jeśli zawiera on patterns, echo jest wyłączone.

Jeśli zawiera Hi następuje przestrzeni echo jest włączona igsub służy do modyfikowania linii, aby pozbyć się wszystkiego, aż do Hi.

Następnie niezależnie od tego linia (ewentualnie zmodyfikowana) jest wyświetlana po włączeniu flagi echo.

Teraz nie będzie to przypadki brzegowe, takie jak:

  • linie zawierające dwa wystąpienia Hi; lub
  • linie zawierające coś przed z patterns.

Nie określiłeś sposobu ich obsługi, więc nie zawracałem sobie głowy, ale podstawowa koncepcja powinna być taka sama.

+0

Wielkie dzięki za odpowiedź i szczegółowy opis paxdiablo, twój soln. działa jak marzenie :-). W moim przypadku nie powtarzam powtarzających się słów wzorców wzdłuż tej samej linii ani żadnych słów występujących przed "wzorami". W moim scenariuszu zawsze mogę zidentyfikować początek linii, od której chciałbym odrzucić wszystko, a ta linia zawsze zaczyna się od tego samego wzorca. Jeszcze raz dziękuję za odpowiedź, bardzo doceniane :-) –

+0

Kilka problemów: 1) "^. * Cześć" to to samo co "Cześć" w RE, 2) Nie musisz podawać 0 jako trzeciego argumentu dla * sub(), 3) Nie potrzebujesz gsub(), gdy chcesz zastąpić tylko 1 wystąpienie, i 4) "{if (echo == 1) {print}}" jest równoważne tylko "echo" na jego. –

+0

Ed. Re 1, nie, nie jest, a nie kiedy zastępujesz - różnica między subboksem a cześć lub wszystko na linii aż do cześć. Inne punkty są ważne, ale w większości stylistyczne. – paxdiablo

3

Updated rozwiązanie, aby usunąć linię „wzorce”:

$ sed -n '/^Hi/,/patterns/{s/^Hi //;/^patterns/d;p;}' file 
I would like 
to print text 
between these 
+0

Dzięki Guru, działa idealnie! :-) –

2

To może pracować dla Ciebie (GNU sed):

sed '/Hi /!d;s//\n/;s/.*\n//;ta;:a;s/patterns.*$//;tb;$!{n;ba};:b;/^$/d' file 
1

Wystarczy ustawić flagę (f) gdy okaże + zastąpić hi na początku wiersza, jasne, kiedy można znaleźć wzorce, a następnie powołać domyślny wydruk po ustawieniu flagi:

$ awk 'sub(/^Hi /,""){f=1} /patterns/{f=0} f' file 
I would like 
to print text 
between these 
Powiązane problemy