我想找到有“abc”和“efg”的文件,这两个字符串在该文件中的不同行。一个包含以下内容的文件:
blah blah..
blah blah..
blah abc blah
blah blah..
blah blah..
blah blah..
blah efg blah blah
blah blah..
blah blah..
应该匹配。
我想找到有“abc”和“efg”的文件,这两个字符串在该文件中的不同行。一个包含以下内容的文件:
blah blah..
blah blah..
blah abc blah
blah blah..
blah blah..
blah blah..
blah efg blah blah
blah blah..
blah blah..
应该匹配。
当前回答
如果你对你要找的两个字符串'abc'和'efg'之间的距离有一些估计,你可以使用:
grep -r . -e 'abc' -A num1 -B num2 | grep 'efg'
这样,第一个grep将返回'abc' + #num1行,后面是#num2行,第二个grep将筛选所有这些以获得'efg'。 然后您将知道它们同时出现在哪些文件中。
其他回答
用银搜索器:
ag 'abc.*(\n|.)*efg' your_filename
与戒指持有者的答案相似,但用ag代替。银色搜索者的速度优势可能在这里大放异彩。
如果您愿意使用上下文,这可以通过输入来实现
grep -A 500 abc test.txt | grep -B 500 efg
这将显示“abc”和“efg”之间的所有内容,只要它们之间的距离不超过500行。
如果你需要两个单词彼此接近,例如不超过3行,你可以这样做:
find . -exec grep -Hn -C 3 "abc" {} \; | grep -C 3 "efg"
同样的例子,但是只过滤*.txt文件:
find . -name *.txt -exec grep -Hn -C 3 "abc" {} \; | grep -C 3 "efg"
如果你想,你也可以用正则表达式替换grep命令。
我不知道如何用grep做到这一点,但我会用awk做这样的事情:
awk '/abc/{ln1=NR} /efg/{ln2=NR} END{if(ln1 && ln2 && ln1 < ln2){print "found"}else{print "not found"}}' foo
不过,你需要注意如何做到这一点。您希望正则表达式匹配子字符串还是整个单词?适当添加\w标记。此外,虽然这严格符合您陈述的示例,但当abc在efg之后第二次出现时,它并不完全有效。如果你想处理这个问题,在/abc/ case等中添加一个If。
我非常依赖于pcregrep,但是对于更新的grep,您不需要安装它的许多特性。只需使用grep -P。
在OP的问题的例子中,我认为以下选项很好地发挥了作用,第二好的选项符合我对问题的理解:
grep -Pzo "abc(.|\n)*efg" /tmp/tes*
grep -Pzl "abc(.|\n)*efg" /tmp/tes*
我将文本复制为/tmp/test1,删除'g'并保存为/tmp/test2。下面的输出显示,第一个显示匹配的字符串,第二个只显示文件名(典型的-o显示匹配,典型的-l只显示文件名)。请注意,'z'对于多行是必要的,'(.|\n)'意味着匹配'换行符以外的任何内容'或'换行符' -即任何内容:
user@host:~$ grep -Pzo "abc(.|\n)*efg" /tmp/tes*
/tmp/test1:abc blah
blah blah..
blah blah..
blah blah..
blah efg
user@host:~$ grep -Pzl "abc(.|\n)*efg" /tmp/tes*
/tmp/test1
要确定你的版本是否足够新,运行man grep,看看顶部是否出现类似的内容:
-P, --perl-regexp
Interpret PATTERN as a Perl regular expression (PCRE, see
below). This is highly experimental and grep -P may warn of
unimplemented features.
它来自GNU grep 2.10。