Làm cách nào để grep cho nhiều mẫu trên nhiều dòng?


19

Để được chính xác

Some text
begin
Some text goes here.
end
Some more text

và tôi muốn trích xuất toàn bộ khối bắt đầu từ "bắt đầu" đến "kết thúc".

với awk chúng ta có thể làm như awk '/begin/,/end/' text.

Làm thế nào để làm với grep?


Câu trả lời:


14

Đã cập nhật ngày 18 tháng 11 năm 2016 (vì hành vi grep đã thay đổi: grep với tham số -P hiện không hỗ trợ ^$neo [trên Ubuntu 16.04 với kernel v: 4.4.0-21-generic]) ( sửa lỗi (không phải) )

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

lưu ý: đối với các lệnh khác, chỉ cần thay thế các neo '^' & '$' bằng neo mới dòng '\n' ____________________________

Với lệnh grep:

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

Nếu bạn muốn không bao gồm các mẫu "bắt đầu" và "kết thúc" trong kết quả, hãy sử dụng grep với hỗ trợ của Lookbehind và Lookahead.

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

Ngoài ra, bạn có thể sử dụng \Kthông báo thay vì khẳng định của Lookbehind.

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

\Ktùy chọn bỏ qua tất cả mọi thứ trước khi khớp mẫu và bỏ qua mẫu chính nó.
\nđược sử dụng để tránh in các dòng trống từ đầu ra.

Hoặc như @AvinashRaj gợi ý có những grep đơn giản dễ dàng như sau:

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

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

(?s)nói với grep để cho phép dấu chấm khớp với các ký tự dòng mới.
[\s\S]phù hợp với bất kỳ ký tự nào là khoảng trắng hoặc không phải khoảng trắng.

Và đầu ra của chúng mà không bao gồm "bắt đầu" và "kết thúc" như sau:

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

xem thử nghiệm đầy đủ của tất cả các lệnh tại đây ( hết hạn vì hành vi grep với tham số -P bị thay đổi )

Ghi chú:

^chỉ điểm bắt đầu của một dòng và $chỉ điểm cuối của một dòng. những thứ này được thêm vào xung quanh "bắt đầu" và "kết thúc" để khớp với chúng nếu chúng ở một mình trong một dòng.
Trong hai lệnh tôi đã thoát $vì nó cũng sử dụng cho "Thay thế lệnh" ( $(command)) cho phép xuất ra lệnh để thay thế tên lệnh.

Từ người đàn ông 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.

thay đổi grep của bạn grep -Pzo "(?<=begin\n)(.|\n)*(?=\nend)" fileđể không in \nký tự tồn tại trên dòng bắt đầu.
Avinash Raj

Sử dụng công cụ sửa đổi DOTALL để tạo dấu chấm để khớp với cả các ký tự dòng mớigrep -Pzo "(?s)begin.*?end" file
Avinash Raj

Hoặc đơn giản,grep -Pzo "begin[\s\S]*?end" file
Avinash Raj

1
Các siólestion không hoạt động. Nó tạo ra một lỗi: grep: ein nicht geschütztes ^ oder $ wird mit -Pz nicht unterstütztBản dịch của lỗi là một cái gì đó như:grep: a not protected ^ or $ is not supported with -Pz
musbach

1
Vâng, tôi biết, đó là trong câu trả lời của bạn. Tôi chắc chắn rằng nó hoạt động khi bạn đăng bài này, nhưng hãy thử lại ngày hôm nay. Hành vi của grepdường như đã thay đổi.
terdon

2

Trong trường hợp bạn grepkhông hỗ trợ cú pháp perl ( -P), bạn có thể thử nối các dòng, khớp với mẫu, sau đó mở rộng lại các dòng như sau:

$ tr '\n' , < foo.txt | grep -o "begin.*end" | tr , '\n'
begin
Some text goes here.
end
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.