Đừng cố sử dụng grep cho việc này, thay vào đó hãy sử dụng awk. Để khớp 2 regexps R1 và R2 trong grep bạn nghĩ nó sẽ là:
grep 'R1.*R2|R2.*R1'
trong khi ở awk nó sẽ là:
awk '/R1/ && /R2/'
nhưng điều gì xảy ra nếu R2
trùng lặp với hoặc là một tập hợp con R1
? Lệnh grep đó đơn giản là không hoạt động trong khi lệnh awk sẽ. Hãy nói rằng bạn muốn tìm các dòng có chứa the
và heat
:
$ echo 'theatre' | grep 'the.*heat|heat.*the'
$ echo 'theatre' | awk '/the/ && /heat/'
theatre
Bạn sẽ phải sử dụng 2 greps và một đường ống cho điều đó:
$ echo 'theatre' | grep 'the' | grep 'heat'
theatre
và tất nhiên nếu bạn thực sự yêu cầu chúng tách biệt, bạn luôn có thể viết trong awk cùng một biểu thức chính quy như bạn đã sử dụng trong grep và có các giải pháp awk thay thế không liên quan đến việc lặp lại các biểu thức chính trong mọi trình tự có thể.
Đặt điều đó sang một bên, điều gì sẽ xảy ra nếu bạn muốn mở rộng giải pháp của mình để phù hợp với 3 regexps R1, R2 và R3. Trong grep đó sẽ là một trong những lựa chọn tồi:
grep 'R1.*R2.*R3|R1.*R3.*R2|R2.*R1.*R3|R2.*R3.*R1|R3.*R1.*R2|R3.*R2.*R1' file
grep R1 file | grep R2 | grep R3
trong khi trong awk nó sẽ là ngắn gọn, rõ ràng, đơn giản, hiệu quả:
awk '/R1/ && /R2/ && /R3/'
Bây giờ, điều gì sẽ xảy ra nếu bạn thực sự muốn khớp các chuỗi ký tự S1 và S2 thay vì regexps R1 và R2? Bạn chỉ đơn giản là không thể làm điều đó trong một cuộc gọi đến grep, bạn phải viết mã để thoát tất cả các siêu dữ liệu RE trước khi gọi grep:
S1=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< 'R1')
S2=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< 'R2')
grep 'S1.*S2|S2.*S1'
hoặc một lần nữa sử dụng 2 greps và một đường ống:
grep -F 'S1' file | grep -F 'S2'
một lần nữa là những lựa chọn tồi trong khi với awk, bạn chỉ cần sử dụng toán tử chuỗi thay vì toán tử regrec:
awk 'index($0,S1) && index($0.S2)'
Bây giờ, nếu bạn muốn khớp 2 regexps trong một đoạn chứ không phải là một dòng thì sao? Không thể được thực hiện trong grep, tầm thường trong awk:
awk -v RS='' '/R1/ && /R2/'
Làm thế nào về toàn bộ tập tin? Một lần nữa không thể được thực hiện bằng grep và tầm thường trong awk (lần này tôi đang sử dụng GNU awk cho multi-char RS vì sự đơn giản nhưng nó không có nhiều mã hơn trong bất kỳ awk nào hoặc bạn có thể chọn một điều khiển mà bạn biết sẽ không ở trong đầu vào để RS thực hiện tương tự):
awk -v RS='^$' '/R1/ && /R2/'
Vì vậy - nếu bạn muốn tìm nhiều regexps hoặc chuỗi trong một dòng hoặc đoạn hoặc tệp thì đừng sử dụng grep, hãy sử dụng awk.