Regex Grep KHÔNG chứa chuỗi


181

Tôi đang chuyển một danh sách các mẫu biểu thức chính quy grepđể kiểm tra tệp syslog. Chúng thường khớp với một địa chỉ IP và mục nhập nhật ký;

grep "1\.2\.3\.4.*Has exploded" syslog.log

Đây chỉ là một danh sách các mẫu như "1\.2\.3\.4.*Has exploded"phần tôi đang vượt qua, trong một vòng lặp, vì vậy tôi không thể vượt qua "-v" chẳng hạn.

Tôi bối rối khi cố gắng thực hiện nghịch đảo ở trên, một dòng KHÔNG khớp với một địa chỉ IP nhất định và lỗi vì vậy "! 1.2.3.4. * Đã phát nổ" sẽ khớp với các dòng syslog cho bất cứ điều gì khác ngoài 1.2.3.4 cho tôi biết nó đã phát nổ . Tôi phải có thể bao gồm một IP để KHÔNG khớp.

Tôi đã thấy nhiều bài viết tương tự trên StackOverflor tuy nhiên họ sử dụng các mẫu regex mà tôi dường như không thể làm việc được grep. Bất cứ ai có thể cung cấp một ví dụ làm việc cho grepxin vui lòng?

CẬP NHẬT: Điều này đang xảy ra trong một kịch bản như thế này;

patterns[1]="1\.2\.3\.4.*Has exploded"
patterns[2]="5\.6\.7\.8.*Has died"
patterns[3]="\!9\.10\.11\.12.*Has exploded"

for i in {1..3}
do
 grep "${patterns[$i]}" logfile.log
done

Bạn có nghĩa là đôi khi bạn muốn khớp một mẫu, nhưng những lần khác muốn khớp mọi thứ trừ một mẫu nhất định? (điều này có vẻ như là một yêu cầu kỳ lạ, nhưng bất cứ điều gì). Trong trường hợp đó, tại sao bạn không lặp lại hai danh sách mẫu khác nhau?
beerbajay

Vâng, tôi không rành về regex; Tôi không muốn grep cho "Đã phát nổ" vì tôi không muốn biết điều này về mọi thiết bị ghi nhật ký, vì vậy tôi có thể bằng cách nào đó grep cho "Đã phát nổ" và! 9.10.11.12 trong một tuyên bố?
jwbensley

Nếu bạn hoàn toàn phải làm điều đó trong một tuyên bố, thì những cái nhìn tiêu cực là cách để đi, như Neil gợi ý. Xem bình luận của tôi ở đó.
beerbajay

Sử dụng so khớp regex theo kiểu PCRE và xác nhận nhìn tiêu cực, theo câu trả lời của @Neil: các patterns[3]="\!9\.10\.11\.12.*Has exploded"thay đổi patterns[3]="(?<!9\.10\.11\.12).*Has exploded"grep "${patterns[$i]}" logfile.logthay đổi đối với grep -P "${patterns[$i]}" logfile.logPCRE mặc định giả định nhiều siêu ký tự hơn, do đó, một số lối thoát có thể cần phải được xóa khỏi các biểu thức khớp khác.
Codex24

Câu trả lời:


341

grepphù hợp, grep -vkhông nghịch đảo. Nếu bạn cần "khớp A nhưng không phải B", bạn thường sử dụng đường ống:

grep "${PATT}" file | grep -v "${NOTPATT}"

Điều này sẽ đi vào giữa một vòng lặp như tôi đã đề cập và tôi chỉ chuyển MẪU cho grep để tôi không thể sử dụng "-v" như tôi đã đề cập. Tôi chỉ lặp đi lặp lại một danh sách các MẪU và chuyển đến grep.
jwbensley

1
Bạn thực sự có thể sử dụng -vvà bạn có thể sử dụng nó trong một vòng lặp. Có lẽ bạn cần phải cụ thể hơn về những hạn chế của mình, hoặc có lẽ bạn có một quan niệm sai lầm về cách kịch bản của bạn nên hoạt động. Hãy thử đăng một số mã.
beerbajay

Cảm ơn beerbajay, tôi đã thêm một đoạn mã được cắt vào bài viết gốc để đưa ra một số bối cảnh. Bạn có thấy những gì tôi có nghĩa là bây giờ?
jwbensley

Câu trả lời này không hoàn toàn chính xác nhưng bạn đã viết khá nhiều biabajay, tôi cần suy nghĩ lại về vòng lặp và sử dụng -v cuối cùng. Cảm ơn con trỏ;)
jwbensley

1
Nhưng nếu A gồm B thì sao? Nói cách khác, nếu tôi muốn ghép các dòng không có A các dòng với AB thì sao? Một đường ống sẽ không hoạt động.
pawamoy

15
(?<!1\.2\.3\.4).*Has exploded

Bạn cần chạy cái này với -P để có cái nhìn tiêu cực (biểu thức chính quy Perl), vì vậy lệnh là:

grep -P '(?<!1\.2\.3\.4).*Has exploded' test.log

Thử cái này. Nó sử dụng cái nhìn tiêu cực để bỏ qua dòng nếu nó được đặt trước 1.2.3.4. Mong rằng sẽ giúp!


1
Tôi khá chắc chắn rằng grepkhông hỗ trợ nhìn. Trừ khi bạn đang sử dụng Gnu grepvà sử dụng --Ptham số để làm cho nó sử dụng công cụ PCRE.
Tim Pietzcker

Không, grep không hỗ trợ loại Regex này; $ grep -P (? <\! 1 \ .2 \ .3 \ .4) test.log -bash: lỗi cú pháp gần mã thông báo bất ngờ `('
jwbensley

Bạn sẽ cần trích dẫn regex nếu nó chứa các ký tự sẽ được giải thích bởi shell.
beerbajay

trích dẫn chính xác: grep -P '(?<!1\.2\.3\.4) Has exploded' test.logLưu ý rằng giao diện chỉ hoạt động trên các ký tự ngay trước phần khớp của biểu thức, vì vậy nếu có những thứ khác giữa địa chỉ và thông báo, ví dụ: 1.2.3.4 FOO Has explodedđiều này sẽ không hoạt động.
beerbajay

@TimPietzcker, rất quan sát. Tôi sẽ thêm nó vào câu hỏi. Ngoài ra, xin lưu ý rằng có một .*cái nhìn tiêu cực sau khi ví dụ của anh ấy cũng có nó, tôi tưởng tượng có thể có văn bản khác ở giữa.
Neil

2
patterns[1]="1\.2\.3\.4.*Has exploded"
patterns[2]="5\.6\.7\.8.*Has died"
patterns[3]="\!9\.10\.11\.12.*Has exploded"

for i in {1..3}
 do
grep "${patterns[$i]}" logfile.log
done

nên giống như

egrep "(1\.2\.3\.4.*Has exploded|5\.6\.7\.8.*Has died)" logfile.log | egrep -v "9\.10\.11\.12.*Has exploded"    
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.