2013-05-20 14 views
7

Proszę mi pomóc w użyciu sed. Mam plik jak poniżej.Sed do wyodrębniania tekstu między dwoma ciągami

START=A 
    xxxxx 
    xxxxx 
END 
START=A 
    xxxxx 
    xxxxx 
END 
START=A 
    xxxxx 
    xxxxx 
END 
START=B 
    xxxxx 
    xxxxx 
END 
START=A 
    xxxxx 
    xxxxx 
END 
START=C 
    xxxxx 
    xxxxx 
END 
START=A 
    xxxxx 
    xxxxx 
END 
START=D 
    xxxxx 
    xxxxx 
END 

Chcę uzyskać tekst między START = A, END. Użyłem poniższego zapytania.

sed '/^START=A/,/^END/!d' input_file 

Problemem tutaj jest jestem coraz

START=A 
    xxxxx 
    xxxxx 
END 
START=D 
    xxxxx 
    xxxxx 
END 

zamiast

START=A 
    xxxxx 
    xxxxx 
END 

Sed znajdzie łapczywie.

Proszę mi pomóc w rozwiązaniu tego problemu.

Z góry dziękuję.

Czy mogę użyć AWK do osiągnięcia powyższych?

Odpowiedz

19
sed -n '/^START=A$/,/^END$/p' data 

Opcja -n oznacza, że ​​domyślnie nie drukuje się; następnie skrypt mówi: "drukuj pomiędzy wierszem zawierającym START=A i następnym END.

można również zrobić z awk:

Wzór może składać się z dwóch oddzielonych wzorów przecinkiem; w tym przypadku akcja jest wykonywana dla wszystkich linii od wystąpienia pierwszego wzorca, chociaż wystąpienie drugiego.

(od man awk na Mac OS X).

awk '/^START=A$/,/^END$/ { print }' data 

Biorąc zmodyfikowaną postacią pliku danych w pytaniu:

START=A 
    xxx01 
    xxx02 
END 
START=A 
    xxx03 
    xxx04 
END 
START=A 
    xxx05 
    xxx06 
END 
START=B 
    xxx07 
    xxx08 
END 
START=A 
    xxx09 
    xxx10 
END 
START=C 
    xxx11 
    xxx12 
END 
START=A 
    xxx13 
    xxx14 
END 
START=D 
    xxx15 
    xxx16 
END 

Wyjście za pomocą GNU sed lub Mac OS X (BSD) sed, a przy użyciu GNU awk lub BSD awk, jest to samo:

START=A 
    xxx01 
    xxx02 
END 
START=A 
    xxx03 
    xxx04 
END 
START=A 
    xxx05 
    xxx06 
END 
START=A 
    xxx09 
    xxx10 
END 
START=A 
    xxx13 
    xxx14 
END 

Zobacz, jak zmodyfikowałem plik danych, aby łatwiej było zobaczyć, gdzie różne bloki danych są drukowane ca mnie z pliku.

Jeśli masz inne wymagania dotyczące wyjścia (takie jak "tylko pierwszy blok pomiędzy START = A i END" lub "tylko ostatni ..."), to musisz wyraźnie to wyrazić w pytaniu.

+1

Dzięki za odpowiedź. Potrzebuję tekstu pomiędzy START = A i następnym ENDem, powyższy podaje dane pomiędzy START = A i ostatnim END. Mam nadzieję, że masz mój problem. – ranganath111

+0

Nie, nie ma. Zarówno skrypty 'awk', jak i' sed' - przynajmniej na moim komputerze z moją kopią dostarczonego pliku danych - drukują 5 bloków danych pomiędzy 'START = A' i' END', a bloki z 'START = B' do 'END',' START = C' do 'END' i' START = D' do 'END' są pomijane w danych wyjściowych. Na jakiej platformie testujesz? Którą wersję "sed" używasz? Którą wersję 'awk' używasz? (Zwracam uwagę, że twoje dane testowe powtarza się dosłownie w blokach pomiędzy "START = A" i "END". Byłoby znacznie lepiej, gdybyś miał różne linie pomiędzy, abyś mógł zobaczyć, które linie są drukowane.) –

+0

Kiedy testuję to , początkowe i końcowe toki są uwzględnione w danych wyjściowych, natomiast miałem wrażenie, że OP chciał jedynie danych MIĘDZY nimi. –

2

Twoje wyrażenie sed ma spację przed końcem, tj. / ^END/. Tak więc sed otrzymuje wzór początkowy, ale nie otrzymuje wzoru końcowego i kontynuuje drukowanie do końca. Użyj sed '/^START=A/, /^END/!d' input_file (zawiadomienie /^END/)

+0

Dobra uwaga na temat miejsca w regex 'sed', ale sprawia, że ​​cytowany wynik jest jeszcze bardziej zagadkowy (jak w" Nie mogę odtworzyć cytowane wyjście z oryginalnym scenariuszem, ale usuń przestrzeń zewnętrzną i działa dobrze, aczkolwiek cackhanded "). Możesz przynajmniej uprościć ostatnią część skryptu 'awk' do'/END/{flag = 0} ', która może ustawić flagę na zero, kiedy było już zero, ale to nie zaszkodzi. Możesz również użyć '/ START = A,,/END/{print}', co jest znacznie prostsze. –

+0

tak, '/ START = A /,/END/{print}' to jest o wiele prostsze, ale jest już pokazane w twojej odpowiedzi :) Właśnie bawiłem się flagą :). Właściwie, po rozwiązaniu 'awk', które podałeś, nie musi robić nic więcej. Usuwam moje rozwiązanie "awk". Mogłoby to doprowadzić do większego zamieszania niż zrobić coś dobrego: P – abasu

+0

tak .. Mam to .. Dzięki dużo – ranganath111

3

Wersja podstawowa ...

sed -n '/START=A/,/END/p' yourfile 

Bardziej wytrzymała wersja ...

sed -n '/^ *START=A *$/,/^ *END *$/p' yourfile 
+0

możesz wyjaśnić, co ',' oznacza w ciągu wzoru sed? –

+0

@Vikrant - ',' oddziela dwie części * zakresu * zdefiniowanego przez dwa wyrażenia regularne, tak że linie między pierwszym wzorem a drugim wzorem są zwracane. – starfry

Powiązane problemy