Не пытайтесь использовать grep для этого, используйте вместо этого awk. Чтобы сопоставить 2 регулярных выражения R1 и R2 в grep, можно подумать, что это будет:
grep 'R1.*R2|R2.*R1'
в то время как в awk это будет:
awk '/R1/ && /R2/'
но что, если R2
перекрывается или является подмножеством R1
? Эта команда grep просто не будет работать, в то время как команда awk будет работать. Допустим, вы хотите найти строки, которые содержат the
и heat
:
$ echo 'theatre' | grep 'the.*heat|heat.*the'
$ echo 'theatre' | awk '/the/ && /heat/'
theatre
Для этого вам нужно использовать 2 greps и трубу:
$ echo 'theatre' | grep 'the' | grep 'heat'
theatre
и, конечно, если вы действительно требовали, чтобы они были отдельными, вы всегда можете написать в awk то же регулярное выражение, которое вы использовали в grep, и есть альтернативные решения awk, которые не предполагают повторение регулярных выражений в каждой возможной последовательности.
Если оставить в стороне, что делать, если вы хотите расширить свое решение для соответствия 3 регулярным выражениям R1, R2 и R3. В grep это был бы один из этих неудачных вариантов:
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
в то время как в awk это будет кратким, очевидным, простым, эффективным:
awk '/R1/ && /R2/ && /R3/'
Теперь, что если вы действительно хотите сопоставить литеральные строки S1 и S2 вместо регулярных выражений R1 и R2? Вы просто не можете сделать это за один вызов grep, вы должны либо написать код, чтобы экранировать все метасхемы RE, прежде чем вызывать grep:
S1=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< 'R1')
S2=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< 'R2')
grep 'S1.*S2|S2.*S1'
или снова используйте 2 greps и трубу:
grep -F 'S1' file | grep -F 'S2'
что опять-таки плохой выбор, тогда как с помощью awk вы просто используете строковый оператор вместо оператора регулярного выражения:
awk 'index($0,S1) && index($0.S2)'
А что если вы хотите сопоставить 2 регулярных выражения в абзаце, а не в строке? Не может быть сделано в grep, тривиально в awk:
awk -v RS='' '/R1/ && /R2/'
Как насчет всего файла? Снова не может быть сделано в grep и тривиально в awk (на этот раз я использую GNU awk для multi-char RS для краткости, но это не намного больше кода в любом awk, или вы можете выбрать контрольный char, который вы не знаете быть на входе для RS, чтобы сделать то же самое):
awk -v RS='^$' '/R1/ && /R2/'
Итак, если вы хотите найти несколько регулярных выражений или строк в строке, абзаце или файле, не используйте grep, используйте awk.