Jak grep dla wielu wzorów na wielu liniach?

Odpowiedzi:

14

Zaktualizowano 18 listopada 2016 r. (Ponieważ zmieniono zachowanie grep: grep z parametrem -P nie obsługuje teraz ^i $zakotwicza [w Ubuntu 16.04 z jądrem v: 4.4.0-21-generic]) ( niepoprawna (nie) poprawka )

$ grep -Pzo "begin(.|\n)*\nend" file
begin
Some text goes here.  
end

Uwaga: w przypadku innych poleceń po prostu zamień kotwice „^” i „$” na kotwicę nowej linii '\n' ______________________________

Z poleceniem grep:

grep -Pzo "^begin\$(.|\n)*^end$" file

Jeśli nie chcesz uwzględniać wzorców „początek” i „koniec”, użyj grep z obsługą Lookbehind i Lookahead.

grep -Pzo "(?<=^begin$\n)(.|\n)*(?=\n^end$)" file

Możesz także użyć \Kpowiadomienia zamiast twierdzenia Lookbehind.

grep -Pzo "^begin$\n\K(.|\n)*(?=\n^end$)" file

\Kopcja zignoruj ​​wszystko przed dopasowaniem wzorca i zignoruj ​​sam wzorzec.
\nsłuży do unikania drukowania pustych linii z wydruku.

Lub, jak sugeruje @AvinashRaj, istnieje prosty łatwy grep w następujący sposób:

grep -Pzo "(?s)^begin$.*?^end$" file

grep -Pzo "^begin\$[\s\S]*?^end$" file

(?s)mówi grep, aby kropka pasowała do znaków nowej linii.
[\s\S]dopasowuje dowolny znak, który jest albo spacją, albo spacją.

Ich wyniki bez uwzględnienia „początku” i „końca” są następujące:

grep -Pzo "^begin$\n\K[\s\S]*?(?=\n^end$)" file # or grep -Pzo "(?<=^begin$\n)[\s\S]*?(?=\n^end$)"

grep -Pzo "(?s)(?<=^begin$\n).*?(?=\n^end$)" file

zobacz pełny test wszystkich poleceń tutaj ( przestarzałe, ponieważ zachowanie grep z parametrem -P zostało zmienione )

Uwaga:

^wskaż początek linii i $wskaż koniec linii. dodawano je do „początku” i „końca”, aby dopasować je, jeśli są sami w linii.
W dwóch poleceniach uciekłem, $ponieważ używa on również funkcji „Command Substitution” ( $(command)), która umożliwia wyjście polecenia zastępując nazwę polecenia.

Od man grep:

-o, --only-matching
      Print only the matched (non-empty) parts of a matching line,
      with each such part on a separate output line.

-P, --perl-regexp
      Interpret PATTERN as a Perl compatible regular expression (PCRE)

-z, --null-data
      Treat the input as a set of lines, each terminated by a zero byte (the ASCII 
      NUL character) instead of a newline. Like the -Z or --null option, this option 
      can be used with commands like sort -z to process arbitrary file names.
αғsнιη
źródło
zmień grep, grep -Pzo "(?<=begin\n)(.|\n)*(?=\nend)" fileaby nie drukować \nznaku, który istnieje na początku linii.
Avinash Raj
Użyj modyfikatora DOTALL, aby kropka pasowała również do znaków nowego wierszagrep -Pzo "(?s)begin.*?end" file
Avinash Raj
Lub po prostugrep -Pzo "begin[\s\S]*?end" file
Avinash Raj
1
Sytuacja nie działa. Powoduje błąd: grep: ein nicht geschütztes ^ oder $ wird mit -Pz nicht unterstütztTłumaczenie błędu jest coś w stylu:grep: a not protected ^ or $ is not supported with -Pz
musbach
1
Tak, wiem, to twoja odpowiedź. Jestem pewien, że zadziałało, kiedy to opublikowałeś, ale spróbuj ponownie dzisiaj. Zachowanie grepwydaje się zmieniły.
terdon
2

Jeśli grepnie obsługujesz składni perl ( -P), możesz spróbować połączyć linie, dopasować wzór, a następnie ponownie rozwinąć linie, jak poniżej:

$ tr '\n' , < foo.txt | grep -o "begin.*end" | tr , '\n'
begin
Some text goes here.
end
kenorb
źródło