Làm thế nào tôi có thể tìm kiếm một mẫu nhiều dòng trong một tệp?


128

Tôi cần tìm tất cả các tệp có chứa một mẫu chuỗi cụ thể. Giải pháp đầu tiên xuất hiện trong đầu là sử dụng find piped với xargs grep :

find . -iname '*.py' | xargs grep -e 'YOUR_PATTERN'

Nhưng nếu tôi cần tìm các mẫu trải dài trên nhiều dòng, tôi bị mắc kẹt vì vanilla grep không thể tìm thấy các mẫu đa dòng.



2
Cái này cũ hơn, vì vậy tôi muốn nói nó không phải là bản sao :)
rogerdpack

@rogerdpack Khi đánh dấu các câu hỏi là trùng lặp, tuổi của câu hỏi là mối quan tâm thứ ba, sau số lượng và chất lượng câu trả lời và chất lượng của câu hỏi.
tripleee

Câu trả lời:


98

Vì vậy, tôi phát hiện ra pcregrep là viết tắt của Perl Tương thích Biểu thức chính quy tương thích Perl .

Ví dụ: bạn cần tìm các tệp trong đó biến ' _name ' là ngay lập tức theo sau là biến ' _descrip ':

find . -iname '*.py' | xargs pcregrep -M '_name.*\n.*_description'

Mẹo: bạn cần bao gồm ký tự ngắt dòng trong mẫu của bạn. Tùy thuộc vào nền tảng của bạn, nó có thể là '\ n', \ r ',' \ r \ n ', ...


7
Như được đề cập bởi halka bên dưới, "bạn cũng có thể thuyết phục ký tự đại diện dấu chấm để khớp với dòng mới nếu bạn thêm (?) Vào biểu thức thông thường của mình". Sau đó sử dụng grep với perl regex bằng cách thêm -P. tìm thấy . -exec grep -nHP '(? s) CHỌN. {1,60} TỪ. {1,20} tên_bảng' '{}' \;
Jim

8
pcregrepcó sẵn trên mac vớibrew install pcre
Jared Beck

1
Thậm chí tốt hơn: cũng sử dụng -Hin tên tệp trước mỗi trận đấu : pcregrep -HM.
Ciro Santilli 郝海东 冠状 病 事件

97

Tại sao bạn không đi cho awk :

awk '/Start pattern/,/End pattern/' filename

2
Điều này dễ hiểu hơn nhiều và sử dụng awkđi kèm với hầu hết các hệ thống * nix.
Ali Karbassi

24
đẹp! Có cách nào để làm cho trận đấu này không tham lam?
marcin

3
Làm thế nào bạn chỉ in tên tệp khi có một trận đấu?
bibstha

2
Bạn có thể hiển thị số dòng của các trận đấu với awk '/Start pattern/,/End pattern/ {printf NR " "; print}' filename. Bạn có thể làm cho nó đẹp hơn bằng cách cho các số dòng có chiều rộng cố định : awk '/Start pattern/,/End pattern/ {printf "%-4s ", NR; print}' filename.
Robert

Điều này dường như hoạt động độc đáo trên một tệp, tuy nhiên, nếu tôi muốn tìm kiếm trong nhiều tệp thì sao?
Jinstrong

84

Dưới đây là ví dụ sử dụng GNUgrep :

grep -Pzo '_name.*\n.*_description'

-z/ --null-dataCoi dữ liệu đầu vào và đầu ra là chuỗi các dòng.

Xem thêm tại đây


1
Điều đó chỉ chiếm một nhân vật mới, tôi nghĩ vậy.
Đám mây

1
Tôi không thể sử dụng grep cho tìm kiếm nhiều dòng, mà không sử dụng cờ -zđể nó không phân chia tìm kiếm trên một dòng và -ochỉ in một phần phù hợp.
bbaja42

Tôi thấy rằng -o đã khiến nó không in được bất cứ thứ gì, nhưng -l đã làm việc để có được một danh sách các tập tin (lệnh của tôi là grep -rzl pattern *, -rzo không hoạt động)
Benubird

5
Tôi khuyên dùng '' grep -Pazo '' thay vì '' -Pzo '' cho các tệp không phải ASCII. Tốt hơn vì chuyển đổi -z trên các tệp không phải ASCII có thể kích hoạt hành vi "dữ liệu nhị phân" của grep làm thay đổi giá trị trả về. Chuyển đổi '' -a | --text '' ngăn chặn điều đó.
rloth

Không hoạt động trên Mac với git được cài đặt bởibrew reinstall --with-pcre git
Quanlong

21

grep -Pcũng sử dụng libpcre, nhưng nhiều cài đặt rộng rãi hơn. Để tìm một titlephần hoàn chỉnh của tài liệu html, ngay cả khi nó kéo dài nhiều dòng, bạn có thể sử dụng phần này:

grep -P '(?s)<title>.*</title>' example.html

dự án PCRE thực hiện theo tiêu chuẩn perl, hãy sử dụng tài liệu perl để tham khảo:


Hmm đã thử điều này ngay bây giờ và dường như không hoạt động ... gist.github.com/rdp/0286d91624930bd11d0169d6a6337c33
rogerdpack

Tôi không biết grep có tùy chọn này. Có lẽ vì điều này: Đây là tính thử nghiệm cao và grep -P có thể cảnh báo các tính năng chưa được thực hiện. ; đó là theo CentOS 7. Theo Fedora 29: Đây là thử nghiệm và grep -P có thể cảnh báo các tính năng chưa được thực hiện . Tất nhiên trong BSD grep nó không có ở đó. Sẽ rất tuyệt nếu nó không thử nghiệm nhưng thật tuyệt khi được nhắc về nó - mặc dù tôi có khả năng sử dụng nó.
Pryftan

17

Đây là một ví dụ hữu ích hơn:

pcregrep -Mi "<title>(.*\n){0,5}</title>" afile.html

Nó tìm kiếm thẻ tiêu đề trong một tệp html ngay cả khi nó kéo dài tới 5 dòng.

Dưới đây là một ví dụ về các dòng không giới hạn:

pcregrep -Mi "(?s)<title>.*</title>" example.html 

4
cảm ơn vì điều đó. Tôi đã bị mắc kẹt khi không nhận ra rằng một ký tự đại diện sẽ không phù hợp với nhân vật dòng mới.
matt

7
@matt: bạn cũng có thể thuyết phục ký tự đại diện chấm để khớp với các dòng mới nếu bạn thêm (?s)vào biểu thức thông thường của mình, như vậy:"(?s)<html>.*</html>"
mỡomir.brindza

@matt Tất nhiên bạn có thể kiểm tra $(ở cuối mẫu) để biểu thị đó là cuối dòng - mặc dù điều đó không giống với việc giúp bạn tìm nhiều mẫu dòng. Xem thêm glob(7). Bạn cũng có thể tìm thấy trang web này quan tâm: regular-expressions.info
Pryftan


4

Bạn có thể sử dụng sàng thay thế grep tại đây (từ chối trách nhiệm: Tôi là tác giả).

Nó hỗ trợ kết hợp đa dòng và giới hạn tìm kiếm các loại tệp cụ thể ngoài hộp:

sift -m --files '* .py' 'YOU_PATTERN'

(tìm kiếm tất cả các tệp * .py cho mẫu regex đa dòng đã chỉ định)

Nó có sẵn cho tất cả các hệ điều hành chính. Hãy xem trang mẫu để xem làm thế nào nó có thể được sử dụng để trích xuất các giá trị đa dòng từ tệp XML.


3

Câu trả lời này có thể hữu ích:

Regex (grep) cho tìm kiếm nhiều dòng cần thiết

Để tìm đệ quy, bạn có thể sử dụng cờ -R (đệ quy) và --incoide (mẫu GLOB). Xem:

Sử dụng cú pháp grep --exclude / - bao gồm để không grep qua các tệp nhất định


@ Ɖihua eezeƦ lưu ý rằng việc chỉnh sửa bài đăng trong LQP ( stackoverflow.com/review/low-quality-posts/19341146 ) làm mất hiệu lực đánh giá, vì vậy chỉ cần chỉnh sửa nếu bạn chắc chắn bài đăng cần được duy trì.
fedorqui 'SO ngừng làm hại'

2

@Marcin: ví dụ awk không tham lam:

awk '{if ($0 ~ /Start pattern/) {triggered=1;}if (triggered) {print; if ($0 ~ /End pattern/) { exit;}}}' filename

2
perl -ne 'print if (/begin pattern/../end pattern/)' filename

Điều này in toàn bộ tập tin mặc dù
Herbert

1

Tùy chọn sử dụng ex/ vitrình chỉnh sửa và sao (cú pháp tương tự awksed):

ex +"/string1/,/string3/p" -R -scq! file.txt

aaađiểm bắt đầu của bạn ở đâu và bbblà văn bản kết thúc của bạn.

Để tìm kiếm đệ quy, hãy thử:

ex +"/aaa/,/bbb/p" -scq! **/*.py

Lưu ý: Để bật **cú pháp, hãy chạy shopt -s globstar(Bash 4 hoặc zsh).

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.