Jak wybrać pierwsze wystąpienie między dwoma wzorami, w tym nimi

27

Jak mogę wybrać pierwsze wystąpienie między dwoma wzorami, w tym nimi. Najlepiej używając sedlub awk.

Mam:

text
something P1 something
content1
content2
something P2 something
text
something P1 something
content3
content4
something P2 something
text

Chcę pierwszego wystąpienia linii między P1 i P2 (w tym linii P1 i linii P2):

something P1 something
content1
content2
something P2 something
kofucii
źródło

Odpowiedzi:

22
sed '/P1/,/P2/!d;/P2/q'

... wykona zadanie przenośnie, dusuwając wszystkie linie, które !nie mieszczą się w zakresie, a następnie qwykonując pierwszy raz, gdy napotka koniec zakresu. Nie zawiedzie dla P2 poprzedzających P1 i nie wymaga składni specyficznej dla GNU, aby pisać po prostu.

mikeserv
źródło
Doskonały! O wiele lepszy niż mój.
muru
1
@muru - Często łatwiej jest uniknąć zniekształceń, jeśli próbujesz celować w autodruk - pozwól, aby cykl zadziałał za ciebie. W każdym razie to nawyk. Myślę, że to prawdopodobnie najlepiej opisać jako śliw vs pomocą wybranej metody - staram się skończyć negując wzór raczej niż szukaniu.
mikeserv
Zawiesi się podczas przetwarzania ogromnego rozmiaru pliku.
Brain90
@ Brain90 - shouldnt. jeśli możesz w wiarygodny sposób odtworzyć skargę, powinieneś zwrócić się do opiekuna twojego sed... to jest błąd w twoim seduruchomieniu, a nie w powyższym skrypcie.
mikeserv
1
@mikeserv Nie powiedziałbym tego, gdybym nie był. Twoja obawa, czy zależy mi na kilku postaciach, jest dziwna: zauważyłem, że wyrażenie sed działa zarówno /P2/qw moim systemie, jak i bez niego ; to jest to. Byłem ciekawy czegoś i chciałem podzielić się tym, co znalazłem.
Alexej Magura,
8

z awk

awk '/P1/{a=1};a;/P2/{exit}' file
something P1 something
content1
content2
something P2 something
iruvar
źródło
8

W sed:

sed -n '/P1/,/P2/p; /P2/q'
  • -npomija drukowanie domyślne i drukujesz linie między pasującymi zakresami adresów za pomocą ppolecenia.
  • Normalnie byłoby to zgodne z obiema sekcjami, więc wychodzisz z ( q), gdy pierwszy P2pasuje.

To się nie powiedzie, jeśli P2przyjdzie wcześniej P1. Aby poradzić sobie z tą sprawą, spróbuj:

sed -n '/P1/,/P2/{p; /P2/q}'
muru
źródło
1
Nie zgadzam się; odpowiedź mikeserv nie jest lepsza od twojej.
G-Man mówi „Reinstate Monica”
@ g-man - pshaw. ale myślałem tylko o tym samym.
mikeserv
1
@gman - nie. teraz rozumiem. kopalnie znacznie lepiej. no {stack}!
mikeserv
1

Jeśli chcesz pominąć same wzorce, oto awkwersja:

awk '/P2/ {exit} /P1/ {f=1; next} f' file
codeforester
źródło
Pracuje dla mnie. Czy możesz dodać więcej informacji na temat działania polecenia?
0xAffe
1

Prostsze awkrozwiązanie (w połowie drogi między odpowiedzią iruvara a  odpowiedzią Muru , ale bez użycia zmiennej):

awk '/P1/,/P2/ { print }  /P2/ { exit }'

i, jak zauważył muru, jeśli pierwsze P2 pojawi się przed pierwszym P1, to nic nie wydrukuje.

Oczywiście, jeśli chcesz wydrukować wszystkie zakresy P1-P2:

something P1 something
content1
content2
something P2 something
something P1 something
content3
content4
something P2 something

po prostu pomiń exitczęść:

awk '/P1/,/P2/ { print }'
G-Man mówi „Przywróć Monikę”
źródło
1
awk '/P1/,/P2/{print;f=1} f&&/P2/{exit}' data

Wyjdź natychmiast po wydrukowaniu, nie wcześniej.

dedowsdi
źródło
0

Aby pominąć same wzorce i wyświetlić tylko pierwszy pasujący blok w pojedynczym GNU sed:

sed -nre '/STARTPATTERN/ {:a;n;/ENDPATTERN/{b;};p;ba}' file
Santrix
źródło