如何使用grep匹配包含string1和string2的行?

时间:2010-12-20 06:11:49

标签: regex linux string grep

我正在尝试使用grep来匹配包含两个不同字符串的行。我尝试过以下操作,但这会匹配包含 string1 string2 的行,这不是我想要的。

grep 'string1\|string2' filename

那么我如何只与包含两个字符串的行匹配grep

22 个答案:

答案 0 :(得分:193)

我认为这就是你要找的东西:

grep -E "string1|string2" filename

我认为答案是这样的:

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

仅匹配两者都存在的情况,而不是一个或另一个或两者。

答案 1 :(得分:160)

您可以使用grep 'string1' filename | grep 'string2'

或者,grep 'string1.*string2\|string2.*string1' filename

答案 2 :(得分:45)

只需给它多个-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版本的手册,但看起来像是the same on Linux

答案 3 :(得分:26)

在任何地方搜索包含所有单词的文件:

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

第一个grep启动递归搜索(r),忽略大小写(i)并列出(打印出)匹配(l)的文件的名称一个术语('action'带有单引号)出现在文件的任何位置。

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

您将获得的最终文件列表是包含这些术语的文件,可以按文件中的任何顺序排列。

答案 4 :(得分:14)

如果grep -P选项包含有限perl正则表达式,则可以使用

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

具有处理重叠字符串的优点。使用perl作为grep更简单一些,因为您可以更直接地指定和逻辑:

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

答案 5 :(得分:12)

你的方法差不多,只缺少-w

grep -w 'string1\|string2' filename

答案 6 :(得分:7)

您可以尝试这样的事情:

(pattern1.*pattern2|pattern2.*pattern1)

答案 7 :(得分:5)

正则表达式中的|运算符表示或。也就是说string1或string2匹配。你可以这样做:

grep 'string1' filename | grep 'string2'

将第一个命令的结果传递给第二个grep。这应该只给你两条线。

答案 8 :(得分:3)

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

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

对已接受的答案进行了评论:不,这不做多行;但那也不是问题的作者所要求的。

答案 9 :(得分:2)

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

答案 10 :(得分:2)

假设我们需要在文件测试文件中找到多个单词的计数。 有两种方法可以解决这个问题

1)使用带正则表达式匹配模式的grep命令

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

2)使用egrep命令

egrep -c 'DOG|CAT' testfile 

使用egrep,您无需担心表达式,只需通过管道分隔符分隔单词。

答案 11 :(得分:1)

将要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 

答案 12 :(得分:1)

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

将以任何顺序获取string1和string2的行

答案 13 :(得分:1)

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

这适用于精确的单词匹配和匹配不区分大小写的单词,因为使用了-i

答案 14 :(得分:1)

grep ‘string1\|string2’ FILENAME 

GNU grep版本3.1

答案 15 :(得分:0)

我经常遇到和你一样的问题,我刚写了一段脚本:

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
}

用法:

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

如果愿意,可以将它放在.bashrc中。

答案 16 :(得分:0)

用于多行匹配:

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"

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

答案 17 :(得分:0)

你应该grep这样:

$ grep 'string1' file | grep 'string2'

答案 18 :(得分:0)

请勿尝试使用grep,而应使用awk。要在grep中匹配2个正则表达式R1和R2,您会认为它是:

grep 'R1.*R2|R2.*R1'

在awk中会是:

awk '/R1/ && /R2/'

但是如果R2R1重叠或为the的子集怎么办?该grep命令根本无法工作,而awk命令却可以。假设您要查找包含heat$ echo 'theatre' | grep 'the.*heat|heat.*the' $ echo 'theatre' | awk '/the/ && /heat/' theatre 的行:

$ echo 'theatre' | grep 'the' | grep 'heat'
theatre

您必须为此使用2个抓钩和一个管道:

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

当然,如果您实际上需要将它们分开,则可以始终使用与grep中所用的相同的正则表达式编写awk,并且有一些替代性的awk解决方案,它们不涉及在所有可能的顺序中重复该正则表达式。 >

放在一边,如果您想扩展您的解决方案以匹配3个正则表达式R1,R2和R3,该怎么办。在grep中,这将是这些不佳的选择之一:

awk '/R1/ && /R2/ && /R3/'

awk简洁明了,简单,有效:

S1=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< 'R1')
S2=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< 'R2')
grep 'S1.*S2|S2.*S1'

现在,如果您实际上想匹配文字字符串S1和S2而不是正则表达式R1和R2,该怎么办?您根本无法在一次调用grep中做到这一点,您必须在调用grep之前编写代码以转义所有RE元字符:

grep -F 'S1' file | grep -F 'S2'

或再次使用2个抓钩和一根烟斗:

awk 'index($0,S1) && index($0.S2)'

这仍然是较差的选择,而使用awk时,您仅使用字符串运算符而不是regexp运算符:

awk -v RS='' '/R1/ && /R2/'

现在,如果要在段落而不是一行中匹配2个正则表达式怎么办?无法在grep中完成,在awk中则微不足道:

awk -v RS='^$' '/R1/ && /R2/'

整个文件怎么样?再次无法在grep和awk中实现微不足道(这一次,我为简洁起见将GNU awk用于多字符RS,但是在任何awk中代码都不多,或者您可以选择一个您不会知道的控制字符可以在RS的输入中进行相同的操作):

public class Practice {

   public static void main(String args[]) {
      NewThread ob1 = new NewThread("One");
      NewThread ob2 = new NewThread("Two");
      ob1.t.start();
      ob2.t.start();
      try {
         Thread.sleep(1000);
      } catch(InterruptedException a) {
         System.out.println("Exception a caught");  
      }
   }
}

所以-如果您要在一行,段落或文件中找到多个正则表达式或字符串,则不要使用grep,请使用awk。

答案 19 :(得分:0)

git grep

以下是使用git grep的多种模式的语法:

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

您还可以将模式与 Boolean 表达式结合使用,例如--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 / {{1} },--extended-regexp / -P--perl-regexp等。

相关:

有关 OR 操作,请参见:

答案 20 :(得分:0)

两个字符串都按顺序排列时,请在grep命令之间插入一个模式:

$ grep -E "string1(?.*)string2" file

示例以下行是否包含在名为Dockerfile的文件中:

FROM python:3.8 as build-python
FROM python:3.8-slim

要获取包含以下字符串的行:FROM pythonas build-python,然后使用:

$ grep -E "FROM python:(?.*) as build-python" Dockerfile

然后输出将仅显示包含两个字符串的所有行:

FROM python:3.8 as build-python

答案 21 :(得分:-1)

ripgrep

以下是使用rg的示例:

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

它是最快的grepping工具之一,因为它建立在Rust's regex engine之上,它使用有限自动机,SIMD和积极的文字优化来使搜索变得非常快。

使用它,尤其是在处理大数据时。

另请参见GH-875上的相关功能请求。