Làm thế nào để làm một trận đấu không tham lam trong grep?


Câu trả lời:


276

Bạn đang tìm kiếm một trận đấu không tham lam (hoặc lười biếng). Để có được một kết quả không tham lam trong các biểu thức thông thường, bạn cần sử dụng công cụ sửa đổi ?sau bộ định lượng. Ví dụ bạn có thể đổi .*sang .*?.

Theo mặc định grep, không hỗ trợ các sửa đổi không tham lam, nhưng bạn có thể sử dụng grep -Pđể sử dụng cú pháp Perl.


3
eegg: dot tất cả các sửa đổi còn được gọi là multiline. Đó là một công cụ sửa đổi thay đổi "." khớp hành vi để bao gồm các dòng mới (thông thường nó không). Không có sửa đổi như vậy trong grep, nhưng có trong pcregrep .
A. Wilson

1
Sửa lỗi: Trong hầu hết các hương vị regex hỗ trợ nó, chế độ cho phép .khớp dòng mới được gọi là chế độ DOTALL hoặc chế độ một dòng ; Ruby là người duy nhất gọi nó là multiline . Trong các hương vị khác, multiline là chế độ cho phép các neo ( ^$) khớp với nhau tại các ranh giới dòng. Ruby không có chế độ tương đương vì trong Ruby chúng luôn hoạt động theo cách đó.
Alan Moore

5
-Plà một cái hoàn toàn mới đối với tôi, tôi đã vui vẻ gồng mình trong nhiều năm và chỉ sử dụng -E... rất nhiều năm lãng phí! - Lưu ý đến bản thân: Đọc lại các trang Man như một điều thường xuyên (thậm chí nhiều hơn!), Bạn không bao giờ tiêu hóa đủ các công tắc và tùy chọn.
ocodo

29
Trên một số nền tảng (như Mac OS X) grepkhông hỗ trợ -P, nhưng nếu bạn sử dụng, egrepbạn có thể sử dụng .*?mẫu để đạt được kết quả tương tự. egrep -o 'start.*?end' text.html
SaltyNuts

4
Là một phần mở rộng cho nhận xét @SaltyNuts, Mac OS X không hỗ trợ -Pnhưng -Esẽ gọi egrepdo đó đề xuất .*?hoạt động tốt.
Fredrik Erlandsson

83

Thực tế các .*?công trình duy nhất trong perl. Tôi không chắc cú pháp regrec mở rộng grep tương đương sẽ là gì. May mắn thay, bạn có thể sử dụng cú pháp perl với grep vì vậy grep -Psẽ hoạt động nhưng grep -Etương tự như egrepnó sẽ không hoạt động (nó sẽ rất tham lam).

Xem thêm: http://blog.vinceliu.com/2008/02/non-greedy-THER-expression-matching.html


9
grep -Pkhông hoạt động trong GNU grep 2.9 - chỉ cần thử nó (nó không bị lỗi, chỉ âm thầm không áp dụng ?. Intertestly cũng không phải là lớp không, ví dụ:env|grep '[^\=]*\='
roberto tomás

2
Không có grep -Ptùy chọn hoặc pgreplệnh nào trong Darwin / OS X 10.8 Mountain Lion, nhưng egrephoạt động rất tốt.
Steve HHH

2
Có một pgreplệnh trên hộp OS X 10.9 của tôi, nhưng đó là một chương trình hoàn toàn khác với mục đích là "tìm hoặc báo hiệu các quá trình theo tên".
Desty

@ robertotomás Trả lời bình luận 6 năm ở đây, nhưng .... Tôi cũng nghĩ vậy và sau đó nhận ra mình đang nhận được nhiều trận đấu không tham lam. Chẳng hạn, trên một thiết bị đầu cuối màu, bạn có thể thấy `echo" bbbbb "| grep -P 'b. *? b'` trả về 2 trận đấu.
zzxyz

12

Grep của tôi hoạt động sau khi thử các thứ trong chủ đề này:

echo "hi how are you " | grep -shoP ".*? "

Chỉ cần đảm bảo rằng bạn thêm một khoảng trắng vào mỗi dòng của bạn

(Của tôi là một dòng theo tìm kiếm để nhổ ra từ)


3
-shoPghi nhớ tốt đẹp :)
Mariusz

echo "bbbbb" | grep -shoP 'b.*?b'là một chút kinh nghiệm học tập. Chỉ có điều làm việc cho tôi về mặt rõ ràng là lười biếng.
zzxyz

12

grep

Đối với trận đấu không tham lam trong grepbạn có thể sử dụng một lớp nhân vật bị phủ định. Nói cách khác, cố gắng tránh ký tự đại diện.

Ví dụ: để tìm nạp tất cả các liên kết đến tệp jpeg từ nội dung trang, bạn sẽ sử dụng:

grep -o '"[^" ]\+.jpg"'

Để xử lý nhiều dòng, đặt đầu vào qua xargsđầu tiên. Để thực hiện, sử dụng ripgrep.


3

Câu trả lời ngắn là sử dụng biểu thức chính quy tiếp theo:

(?s)<car .*? model=BMW .*?>.*?</car>
  • (? s) - điều này làm cho một trận đấu trên nhiều dòng
  • . *? - khớp với bất kỳ nhân vật nào, một số lần theo cách lười biếng (khớp tối thiểu)

Một (ít) câu trả lời phức tạp hơn là:

(?s)<([a-z\-_0-9]+?) .*? model=BMW .*?>.*?</\1>

Điều này sẽ làm cho có thể khớp car1 và car2 trong văn bản sau

<car1 ... model=BMW ...>
...
...
...
</car1>
<car2 ... model=BMW ...>
...
...
...
</car2>
  • (..) đại diện cho một nhóm bắt giữ
  • \ 1 trong ngữ cảnh này khớp với mẫu như được khớp gần đây nhất bằng cách chụp nhóm số 1

1

Xin lỗi tôi trễ 9 năm, nhưng điều này có thể hiệu quả với người xem vào năm 2020.

Vì vậy, giả sử bạn có một dòng như "Hello my name is Jello". Bây giờ bạn muốn tìm các từ bắt đầu 'H'và kết thúc bằng 'o', với bất kỳ số lượng ký tự ở giữa. Và chúng tôi không muốn dòng chúng tôi chỉ muốn từ. Vì vậy, chúng ta có thể sử dụng biểu thức:

grep "H[^ ]*o" file

Điều này sẽ trả lại tất cả các từ. Cách thức hoạt động này là: Nó sẽ cho phép tất cả các ký tự thay vì ký tự khoảng trắng ở giữa, theo cách này chúng ta có thể tránh nhiều từ trong cùng một dòng.

Bây giờ bạn có thể thay thế nhân vật không gian bằng bất kỳ nhân vật nào bạn muốn. Giả sử dòng ban đầu là "Hello-my-name-is-Jello", sau đó bạn có thể nhận được các từ bằng cách sử dụng biểu thức:

grep "H[^-]*o" file

0

Tôi biết rằng đó là một chút của một bài viết chết nhưng tôi chỉ nhận thấy rằng điều này làm việc. Nó loại bỏ cả dọn dẹp và dọn dẹp khỏi đầu ra của tôi.

> grep -v -e 'clean\-\?up'
> grep --version grep (GNU grep) 2.20
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.