Сопоставьте две строки в одной строке с grep

Я пытаюсь использовать grep для сопоставления строк, содержащих две разные строки. Я пробовал следующее, но это соответствует строкам, которые содержат строку string1 или, которая не то, что я хочу.

grep 'string1\|string2' filename

Итак, как мне сопоставить с grep только строки, содержащие обе строки?

Ответ 1

Вы можете использовать grep 'string1' filename | grep 'string2'

Или, grep 'string1.*string2\|string2.*string1' filename

Ответ 2

Я думаю, что это то, что вы искали:

grep -E "string1|string2" filename

Я думаю, что ответы вроде этого:

grep 'string1.*string2\|string2.*string1' filename

соответствуют только случаю, когда оба присутствуют, а не один или другой или оба.

Ответ 3

Просто укажите несколько опций -e.

 -e pattern, --regexp=pattern
         Specify a pattern used during the search of the input: an input
         line is selected if it matches any of the specified patterns.
         This option is most useful when multiple -e options are used to
         specify multiple patterns, or when a pattern begins with a dash
         (`-').

Таким образом, команда становится:

grep -e "string1" -e "string2" filename

Примечание. Выше я привел руководство по версиям BSD, но выглядит как то же самое в Linux.

Ответ 4

Поиск файлов, содержащих все слова в любом порядке:

grep -ril \'action\' | xargs grep -il \'model\' | xargs grep -il \'view_type\'

Первый grep запускает рекурсивный поиск (r), игнорируя регистр (i) и перечисляя (распечатывая) имя файлов, которые соответствуют (l) для одного термина ('action' с одинарными кавычками), встречающихся в любом месте файла.

Последующие greps ищут другие термины, сохраняя нечувствительность к регистру и выводя соответствующие файлы.

Окончательный список файлов, которые вы получите, будет содержать те, которые содержат эти термины, в любом порядке в любом месте файла.

Ответ 5

Если у вас есть grep с опцией -P для ограниченного регулярного выражения perl, вы можете использовать

grep -P '(?=.*string1)(?=.*string2)'

который имеет преимущество в работе с перекрывающимися строками. Это несколько более прямолинейно, используя perl как grep, потому что вы можете напрямую указать и логику:

perl -ne 'print if /string1/ && /string2/'

Ответ 6

Ваш метод был почти хорошим, только без -w

grep -w 'string1\|string2' filename

Ответ 7

Вы можете попробовать что-то вроде этого:

(pattern1.*pattern2|pattern2.*pattern1)

Ответ 8

Оператор | в регулярном выражении означает или. То есть либо строка1, либо строка2 будут совпадать. Вы можете сделать:

grep 'string1' filename | grep 'string2'

который будет передавать результаты первой команды во второй grep. Это должно дать вам только строки, которые соответствуют обоим.

Ответ 9

И поскольку люди предложили perl и python, а также запутанные сценарии оболочки, вот простой подход awk:

awk '/string1/ && /string2/' filename

Посмотрев комментарии к принятому ответу: нет, это не делает многострочный; но тогда это также не то, о чем просил автор вопроса.

Ответ 10

Найденные строки, которые начинаются с 6 пробелов и заканчиваются:

 cat my_file.txt | grep
 -e '^      .*(\.c$|\.cpp$|\.h$|\.log$|\.out$)' # .c or .cpp or .h or .log or .out
 -e '^      .*[0-9]\{5,9\}$' # numers between 5 and 9 digist
 > nolog.txt

Ответ 11

Скажем, нам нужно найти количество нескольких слов в файле файла. Есть два способа сделать это

1) Используйте команду grep с шаблоном соответствия регулярных выражений

grep -c '\<\(DOG\|CAT\)\>' testfile

2) Используйте команду egrep

egrep -c 'DOG|CAT' testfile 

С egrep вам не нужно беспокоиться о выражении и просто отделять слова от разделителя труб.

Ответ 12

Поместите строки, которые вы хотите использовать grep, в файл

echo who    > find.txt
echo Roger >> find.txt
echo [44][0-9]{9,} >> find.txt

Затем поиск с использованием -f

grep -f find.txt BIG_FILE_TO_SEARCH.txt 

Ответ 13

grep '(string1.*string2 | string2.*string1)' filename

получит строку с string1 и string2 в любом порядке

Ответ 14

grep -i -w 'string1\|string2' filename

Это работает для точного совпадения слов и совпадения слов без учета регистра, для этого используется -i

Ответ 15

Не пытайтесь использовать 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.

Ответ 16

git grep

Вот синтаксис с использованием git grep с несколькими шаблонами:

git grep --all-match --no-index -l -e string1 -e string2 -e string3 file

Вы также можете комбинировать шаблоны с логическими выражениями, такими как --and, --or и --not.

Обратитесь к представителю man git-Grep за помощью.


--all-match При задании нескольких выражений-шаблонов этот флаг указывается для ограничения соответствия файлам, строки которых соответствуют всем из них.

--no-index Поиск файлов в текущем каталоге, который не управляется Git.

-l/--Files-with-matches/--name-only Показывать только имена файлов.

-e Следующий параметр - это шаблон. По умолчанию используется базовое регулярное выражение.

Другие параметры для рассмотрения:

--threads Количество используемых рабочих потоков grep.

-q/--quiet/--silent Не выводить совпавшие строки; выйти со статусом 0, когда есть совпадение.

Чтобы изменить тип шаблона, вы также можете использовать -G/--basic-regexp (по умолчанию), -F/--Fixed-strings, -e/--extended-regexp, -P/--Perl-regexp, -F file и другие.

Связанные с:

Для операции ИЛИ см.:

Ответ 17

У вас должно быть grep следующее:

$ grep 'string1' file | grep 'string2'

Ответ 18

для многострочного соответствия:

echo -e "test1\ntest2\ntest3" |tr -d '\n' |grep "test1.*test3"

или

echo -e "test1\ntest5\ntest3" >tst.txt
cat tst.txt |tr -d '\n' |grep "test1.*test3\|test3.*test1"

нам просто нужно удалить символ новой строки, и он работает!

Ответ 19

Я часто сталкиваюсь с той же проблемой, что и ваша, и я просто написал фрагмент script:

function m() { # m means 'multi pattern grep'

    function _usage() {
    echo "usage: COMMAND [-inH] -p<pattern1> -p<pattern2> <filename>"
    echo "-i : ignore case"
    echo "-n : show line number"
    echo "-H : show filename"
    echo "-h : show header"
    echo "-p : specify pattern"
    }

    declare -a patterns
    # it is important to declare OPTIND as local
    local ignorecase_flag  filename linum header_flag colon result OPTIND

    while getopts "iHhnp:" opt; do
    case $opt in
        i)
        ignorecase_flag=true ;;
        H)
        filename="FILENAME," ;;
        n)
        linum="NR," ;;
        p)
        patterns+=( "$OPTARG" ) ;;
        h)
        header_flag=true ;;
        \?)
        _usage
        return ;;
    esac
    done

    if [[ -n $filename || -n $linum ]]; then
    colon="\":\","
    fi

    shift $(( $OPTIND - 1 ))

    if [[ $ignorecase_flag == true ]]; then
    for s in "${patterns[@]}"; do
            result+=" && s~/${s,,}/"
    done
    result=${result# && }
    result="{s=tolower(\$0)} $result"
    else
    for s in "${patterns[@]}"; do
            result="$result && /$s/"
    done
    result=${result# && }
    fi

    result+=" { print "$filename$linum$colon"\$0 }"

    if [[ ! -t 0 ]]; then       # pipe case
    cat - | awk "${result}"
    else
    for f in "[email protected]"; do
        [[ $header_flag == true ]] && echo "########## $f ##########"
        awk "${result}" $f
    done
    fi
}

Использование:

echo "a b c" | m -p A 
echo "a b c" | m -i -p A # a b c

Вы можете поместить его в .bashrc, если хотите.

Ответ 20

grep ‘string1\|string2 FILENAME 

GNU grep версия 3.1

Ответ 21

ripgrep

Вот пример использования rg:

rg -N '(?P<p1>.*string1.*)(?P<p2>.*string2.*)' file.txt

Это один из самых быстрых инструментов поиска, поскольку он построен на основе движка регулярных выражений Rust, который использует конечные автоматы, SIMD и агрессивные буквальные оптимизации, чтобы сделать поиск очень быстрым.

Используйте его, особенно когда вы работаете с большими данными.

См. Также запрос связанных функций на GH-875.