我想找到有“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'。 然后您将知道它们同时出现在哪些文件中。

其他回答

这可以通过首先使用tr用其他字符替换换行符来轻松完成:

tr '\n' '\a' | grep -o 'abc.*def' | tr '\a' '\n'

这里,我使用警报字符\a (ASCII 7)来代替换行符。 这在你的文本中几乎找不到,而且grep可以用一个.匹配它,或者专门用\a匹配它。

使用ripgrep可以:

$ rg --multiline 'abc(\n|.)+?efg' test.txt
3:blah abc blah
4:blah abc blah
5:blah blah..
6:blah blah..
7:blah blah..
8:blah efg blah blah

或者其他咒语。

如果你愿意的话。作为换行符计算:

$ rg --multiline '(?s)abc.+?efg' test.txt
3:blah abc blah
4:blah abc blah
5:blah blah..
6:blah blah..
7:blah blah..
8:blah efg blah blah

或者等效于(?s)的是rg -multiline- multiline-dotall

为了回答最初的问题,它们必须在不同的行上:

$ rg——multiline 'abc.*[\n](\n|.)*efg' test.txt

如果你想让它“非贪婪”,这样你就不会用最后一个efg得到第一个abc(把它们分成成对):

$ rg——multiline 'abc.*[\n](\n|.)*?efg的用法

https://til.hashrocket.com/posts/9zneks2cbv-multiline-matches-with-ripgrep-rg

如果你需要两个单词彼此接近,例如不超过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替代方案,它直接支持这一点,通过多行匹配或使用条件——希望它对搜索这里的人有用。下面是示例命令的样子:

多行:

sift -lm 'abc.*efg' testfile

条件:

sift -l 'abc' testfile --followed-by 'efg'

你也可以指定'efg'必须在一定的行数内跟在'abc'后面:

sift -l 'abc' testfile --followed-within 5:'efg'

你可以在sift-tool.org上找到更多信息。

在所有文件中递归搜索(在每个文件中的多行中),同时存在两个字符串(即string1和string2在不同的行中,并且都存在于同一个文件中):

grep -r -l 'string1' * > tmp; while read p; do grep -l 'string2' $p; done < tmp; rm tmp 

在所有文件中递归搜索(在每个文件中的多行中),使用EITHER字符串存在(即string1和string2在不同的行中,并且在同一个文件中存在):

grep -r -l 'string1\|string2' *