Jak wybrać linie pomiędzy dwoma wzorcami znaczników, które mogą wystąpić wielokrotnie w awk / sed

Używając awk lub sed Jak wybrać linie, które występują pomiędzy dwoma różnymi wzorami znaczników? Może być wiele sekcji oznaczonych tymi wzorami.

Na przykład: Załóżmy, że plik zawiera:

abc
def1
ghi1
jkl1
mno
abc
def2
ghi2
jkl2
mno
pqr
stu

I wzorzec początkowy to {[5] } a wzorzec końcowy to mno Więc potrzebuję wyjścia jako:

def1
ghi1
jkl1
def2
ghi2
jkl2

Używam sed do dopasowania wzorca raz:

sed -e '1,/abc/d' -e '/mno/,$d' <FILE>

Czy jest jakiś sposób w sed lub awk aby robić to wielokrotnie aż do końca pliku?

Author: oberlies, 0000-00-00

8 answers

Użyj awk z flagą, aby wywołać wydruk w razie potrzeby:

$ awk '/abc/{flag=1;next}/mno/{flag=0}flag' file
def1
ghi1
jkl1
def2
ghi2
jkl2

Jak to działa?

  • /abc/ dopasowuje linie zawierające ten tekst, podobnie jak /mno/.
  • /abc/{flag=1;next} ustawia flag gdy tekst abc zostanie znaleziony. Potem omija linię.
  • /mno/{flag=0} usuwa flag, gdy tekst mno zostanie znaleziony.
  • finalny flag jest wzorcem z domyślną akcją, którą jest print $0: Jeśli {[5] } jest równe 1, drukowana jest linia.

Dla bardziej szczegółowy opis i przykłady, wraz z przypadkami, gdy wzory są wyświetlane lub nie, zobacz Jak wybrać linie między dwoma wzorami?.

 140
Author: fedorqui,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:56

Używając sed:

sed -n -e '/^abc$/,/^mno$/{ /^abc$/d; /^mno$/d; p; }'

Opcja -n oznacza domyślnie nie Drukuj.

Wzorzec wyszukuje linie zawierające tylko abc do tylko mno, a następnie wykonuje akcje w { ... }. Pierwsza akcja usuwa linię abc, druga linię mno, A p wyświetla pozostałe linie. Możesz rozluźnić wyrażenia regularne w razie potrzeby. Dowolne linie spoza zakresu abc..mno po prostu nie są drukowane.

 35
Author: Jonathan Leffler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-01 08:47:40

To może zadziałać dla Ciebie (GNU sed):

sed '/^abc$/,/^mno$/{//!b};d' file

Usuń wszystkie linie z wyjątkiem tych pomiędzy liniami rozpoczynającymi się abc i mno

 15
Author: potong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-01 09:39:57
sed '/^abc$/,/^mno$/!d;//d' file

Golfs two characters better than ppotong ' s {//!b};d

Puste ukośniki // oznaczają: "użyj ponownie ostatniego użytego wyrażenia regularnego". a polecenie robi to samo co bardziej zrozumiałe:

sed '/^abc$/,/^mno$/!d;/^abc$/d;/^mno$/d' file

This seems to be POSIX :

Jeśli RE jest pusty (tzn. nie podano wzorca) sed zachowuje się tak, jakby ostatnia RE użyta w ostatnio zastosowanym poleceniu (jako adres lub jako część polecenia zastępczego) była określone.

 12
Author: Ciro Santilli 新疆改造中心 六四事件 法轮功,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:33

Z linków poprzedniej odpowiedzi wynika, że ten, który zrobił to dla mnie, uruchamiając ksh na Solarisie, był taki:

sed '1,/firstmatch/d;/secondmatch/,$d'
 4
Author: FanDeLaU,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-12 16:38:10

ODPOWIEDŹ Don_crissti z pokazuje tylko tekst pomiędzy 2 pasującymi wzorami?

firstmatch="abc"
secondmatch="cdf"
sed "/$firstmatch/,/$secondmatch/!d;//d" infile

Który jest znacznie bardziej wydajny niż aplikacja AWK, zobacz Tutaj .

 2
Author: Léo Léopold Hertz 준영,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-13 12:36:28
perl -lne 'print if((/abc/../mno/) && !(/abc/||/mno/))' your_file
 1
Author: Vijay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-01 09:13:08

Coś takiego działa u mnie:

Plik.awk:

BEGIN {
    record=0
}

/^abc$/ {
    record=1
}

/^mno$/ {
    record=0;
    print "s="s;
    s=""
}

!/^abc|mno$/ {
    if (record==1) {
        s = s"\n"$0
    }   
}

Używając: awk -f file.awk data...

Edit: O_o fedorqui rozwiązanie jest o wiele lepsze/ładniejsze niż moje.

 1
Author: pataluc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-11 11:32:58