如何使用grep在同一行中匹配多个字符串?

时间:2022-10-25 00:02:38

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的行匹配,这不是我想要的。

grep 'string1\|string2' filename

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

那么如何只匹配包含两个字符串的行呢?

17 个解决方案

#1


128  

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

你可以使用grep 'string1'文件名| grep 'string2'

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

或者,grep string1。* string2相等\ | string2相等。* string1的文件名

#2


170  

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


42  

Just give it multiple -e options.

只要给它多个-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
         (`-').

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.

注意:上面我引用了BSD版本的手册,但是在Linux上看起来是一样的。

#4


25  

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.

第一个grep启动一个递归搜索(r),忽略case (i)和列出(打印出)在文件中任何位置匹配(l)的文件的名称(“action”和单引号)。

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

随后的greps搜索其他术语,保留大小写不敏感,并列出匹配的文件。

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

您将得到的最终文件列表将包含这些术语的文件,以文件中任何位置的任意顺序排列。

#5


13  

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

如果您有一个带有-P选项的grep,可以使用有限的perl regex,您可以使用它。

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作为grep更简单,因为您可以更直接地指定and逻辑:

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

#6


10  

Your method was almost good, only missing the -w

你的方法几乎是好的,只是漏掉了-w

grep -w 'string1\|string2' filename

#7


7  

You could try something like this:

你可以试试这样的方法:

(pattern1.*pattern2|pattern2.*pattern1)

#8


3  

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

正则表达式中的|运算符表示or。也就是说string1和string2会匹配。你能做的:

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.

它将第一个命令的结果导入第二个grep。这应该只给你匹配这两个的行。

#9


1  

Place the strings you want to grep for into a file

将您想要grep的字符串放到一个文件中

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

Then search using -f

然后使用- f搜索

grep -f find.txt BIG_FILE_TO_SEARCH.txt 

#10


1  

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

找到只以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  

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

假设我们需要在一个文件testfile中找到多个单词的计数。有两种方法

1) Use grep command with regex matching pattern

1)使用regex匹配模式使用grep命令。

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

2) Use egrep command

2)使用egrep命令

egrep -c 'DOG|CAT' testfile 

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

使用白鹭,您不必担心表达式,只需使用管道分隔符分隔单词。

#12


0  

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!

我们只需要删除换行符就可以了!

#13


0  

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

will get line with string1 and string2 in any order

会以任何顺序与string1和string2保持一致吗

#14


0  

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.

如果你愿意,你可以把它放到。bashrc中。

#15


0  

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

正如人们建议的perl和python,以及复杂的shell脚本,这里有一个简单的awk方法:

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.

看了评论对公认的答案:不,这不是多行;但这也不是问题的作者所要求的。

#16


0  

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

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

这适用于精确的单词匹配和匹配不区分大小写的单词

#17


-1  

You should have grep like this:

你应该有这样的grep:

$ grep 'string1' file | grep 'string2'

#1


128  

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

你可以使用grep 'string1'文件名| grep 'string2'

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

或者,grep string1。* string2相等\ | string2相等。* string1的文件名

#2


170  

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


42  

Just give it multiple -e options.

只要给它多个-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
         (`-').

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.

注意:上面我引用了BSD版本的手册,但是在Linux上看起来是一样的。

#4


25  

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.

第一个grep启动一个递归搜索(r),忽略case (i)和列出(打印出)在文件中任何位置匹配(l)的文件的名称(“action”和单引号)。

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

随后的greps搜索其他术语,保留大小写不敏感,并列出匹配的文件。

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

您将得到的最终文件列表将包含这些术语的文件,以文件中任何位置的任意顺序排列。

#5


13  

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

如果您有一个带有-P选项的grep,可以使用有限的perl regex,您可以使用它。

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作为grep更简单,因为您可以更直接地指定and逻辑:

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

#6


10  

Your method was almost good, only missing the -w

你的方法几乎是好的,只是漏掉了-w

grep -w 'string1\|string2' filename

#7


7  

You could try something like this:

你可以试试这样的方法:

(pattern1.*pattern2|pattern2.*pattern1)

#8


3  

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

正则表达式中的|运算符表示or。也就是说string1和string2会匹配。你能做的:

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.

它将第一个命令的结果导入第二个grep。这应该只给你匹配这两个的行。

#9


1  

Place the strings you want to grep for into a file

将您想要grep的字符串放到一个文件中

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

Then search using -f

然后使用- f搜索

grep -f find.txt BIG_FILE_TO_SEARCH.txt 

#10


1  

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

找到只以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  

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

假设我们需要在一个文件testfile中找到多个单词的计数。有两种方法

1) Use grep command with regex matching pattern

1)使用regex匹配模式使用grep命令。

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

2) Use egrep command

2)使用egrep命令

egrep -c 'DOG|CAT' testfile 

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

使用白鹭,您不必担心表达式,只需使用管道分隔符分隔单词。

#12


0  

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!

我们只需要删除换行符就可以了!

#13


0  

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

will get line with string1 and string2 in any order

会以任何顺序与string1和string2保持一致吗

#14


0  

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.

如果你愿意,你可以把它放到。bashrc中。

#15


0  

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

正如人们建议的perl和python,以及复杂的shell脚本,这里有一个简单的awk方法:

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.

看了评论对公认的答案:不,这不是多行;但这也不是问题的作者所要求的。

#16


0  

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

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

这适用于精确的单词匹配和匹配不区分大小写的单词

#17


-1  

You should have grep like this:

你应该有这样的grep:

$ grep 'string1' file | grep 'string2'