How to use grep to match multiple strings in the s

2019-01-10 00:22发布

问题:

I am trying to use grep to match lines that contain two different strings. I have tried the following but this matches lines that contain either string1 or string2 which not what I want.

grep 'string1\|string2' filename

So how do I match with grep only the lines that contain both strings?

回答1:

You can use grep 'string1' filename | grep 'string2'

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



回答2:

I think this is what you were looking for:

grep -E "string1|string2" filename

I think that answers like this:

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

only match the case where both are present, not one or the other or both.



回答3:

Just give it multiple -e options.

 -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
         (`-').

Thus the command becomes:

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

Note: Above I quoted the BSD version’s manual, but looks like it’s the same on Linux.



回答4:

To search for files containing all the words in any order anywhere:

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

The first grep kicks off a recursive search (r), ignoring case (i) and listing (printing out) the name of the files that are matching (l) for one term ('action' with the single quotes) occurring anywhere in the file.

The subsequent greps search for the other terms, retaining case insensitivity and listing out the matching files.

The final list of files that you will get will the ones that contain these terms, in any order anywhere in the file.



回答5:

If you have a grep with a -P option for a limited perl regex, you can use

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

which has the advantage of working with overlapping strings. It's somewhat more straightforward using perl as grep, because you can specify the and logic more directly:

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


回答6:

Your method was almost good, only missing the -w

grep -w 'string1\|string2' filename


回答7:

You could try something like this:

(pattern1.*pattern2|pattern2.*pattern1)


回答8:

The | operator in a regular expression means or. That is to say either string1 or string2 will match. You could do:

grep 'string1' filename | grep 'string2'

which will pipe the results from the first command into the second grep. That should give you only lines that match both.



回答9:

Let's say we need to find count of multiple words in a file testfile. There are two ways to go about it

1) Use grep command with regex matching pattern

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

2) Use egrep command

egrep -c 'DOG|CAT' testfile 

With egrep you need not to worry about expression and just separate words by a pipe separator.



回答10:

Place the strings you want to grep for into a file

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

Then search using -f

grep -f find.txt BIG_FILE_TO_SEARCH.txt 


回答11:

Found lines that only starts with 6 spaces and finished with:

 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


回答12:

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

will get line with string1 and string2 in any order



回答13:

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

This works for exact word match and matching case insensitive words ,for that -i is used



回答14:

for multiline match:

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

or

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

we just need to remove the newline character and it works!



回答15:

I often run into the same problem as yours, and I just wrote a piece of 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 "$@"; do
        [[ $header_flag == true ]] && echo "########## $f ##########"
        awk "${result}" $f
    done
    fi
}

Usage:

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

You can put it in .bashrc if you like.



回答16:

And as people suggested perl and python, and convoluted shell scripts, here a simple awk approach:

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

Having looked at the comments to the accepted answer: no, this doesn't do multi-line; but then that's also not what the author of the question asked for.



回答17:

You should have grep like this:

$ grep 'string1' file | grep 'string2'