2010-12-20 151 views
143

我试图使用grep来匹配包含两个不同字符串的行。我已经尝试了以下,但这匹配线包含string1string2这不是我想要的。如何使用grep匹配同一行中的多个字符串?

grep 'string1\|string2' filename 

那么,如何配合grep仅包含两个字符串行?

+1

相关:https://unix.stackexchange.com/questions/37313/how-do-i- grep-for-patterns- – 2018-01-03 09:06:37

回答

118

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

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

+2

尝试多行 – 2013-03-15 20:47:11

+3

@AlexanderN的确我不能让它与多行工作,这是如此奇怪,它被接受.. – 2013-10-24 03:23:49

+1

这不是一个多行问题。如果它是多行的,grep -P支持Perl风格的正则表达式... – 2014-11-28 15:02:07

3

|运算符在正则表达式中意味着或。也就是说,string1或string2将匹配。你可以这样做:

grep 'string1' filename | grep 'string2' 

这将管道结果从第一个命令到第二个grep。这应该只给你两条线匹配。

+0

你的陈述是真实的,但不回答OP问题 – 2017-07-24 19:03:30

7

你可以尝试这样的事:

(pattern1.*pattern2|pattern2.*pattern1) 
0

你应该有grep这样的:

$ grep 'string1' file | grep 'string2' 
+0

这执行逻辑AND。 OP想要一个逻辑OR。 – 2017-07-24 19:02:55

12

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

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

其中有重叠的字符串工作的优势。这有点更直接使用perlgrep,因为你可以指定和更直接的逻辑:

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

最佳答案。 Shell非常简单快捷,但一旦模式变得复杂,您应该使用Python或Perl(或Awk)。不要打击你的头靠在墙上试图证明它可以在纯贝壳中完成(无论这些日子是什么意思)。提醒人们,这些工具可以用于嵌入到现有shell脚本中的“单行”语法。 – 2014-11-28 15:06:45

159

我想这就是你要找的人:

grep -E "string1|string2" filename 

我认为,答案是这样的:

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

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

+11

不会'grep -e“string1”-e“string2”文件名“做同样的事情吗? – janosdivenyi 2015-02-24 16:07:31

+1

另外egrep'string1 | string2 | string3'文件名可以工作。 – 2015-04-20 08:50:50

+12

这是如何grep为string1或string2。问题清楚地表明他们正在寻找string1和string2。 – 2015-10-08 19:06:23

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" 

我们只需要删除换行符和它的作品!

23

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

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

第一grep的序幕递归搜索(r),忽略大小写(i)和上市(打印出)的名称(l)与文件中任何位置发生的一个词('action'与单引号)匹配的文件。

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

您将获得的文件的最终列表将包含这些条款的文件,文件中任意位置的任何顺序。

+0

同意!我只会注意到,我必须给xargs一个“-d'\ n'”来处理带有空格的文件名。这在Linux上适用于我:'grep -ril'foo'| xargs -d'\ n'grep -il'bar'' – 2017-05-11 21:28:12

10

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

grep -w 'string1\|string2' filename 
+0

这不行! – Ariel 2015-07-22 03:50:49

+1

至少在OS-X和FreeBSD上它确实有效!我的猜测是你还在别的东西上(OP没有定义 - 希望你除了你以外对很多用户都没有正确的回答)。 – Leo 2015-07-23 07:27:13

+0

我在OS-X上。也许我没有正确地做到这一点?看看我做了什么:http://i.imgur.com/PFVlVAG.png – Ariel 2015-07-27 18:13:32

40

只要给它多-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

+11

注意:这匹配任何OP所要求的字符串中的任何一个,而不是两个字符串。 – gustafbstrom 2016-10-05 09:52:14

0

把要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 
1

发现线,只有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 
0
grep '(string1.*string2 | string2.*string1)' filename 

将获得与字符串1和字符串行以任意顺序

+0

与至少前两个答案有什么不同? – luk2302 2017-05-04 15:48:58

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 "[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中。

0

假设我们需要查找文件测试文件中多个单词的计数。 有两种方式去了解它

1)使用与正则表达式匹配模式

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

2)使用egrep的命令

egrep -c 'DOG|CAT' testfile 

随着你不必egrep的担心表达grep命令并用管道分隔符分隔单词。

0

而作为人建议Perl和Python,和令人费解的shell脚本,在这里简单awk的方法:

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

说完看了看评论公认的答案:不,这并不做多-线;但那也不是这个问题的作者所要求的。

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

这适用于完全相符的文字和匹配不区分大小写的话,对于正在使用的-i

相关问题