我想找到有“abc”和“efg”的文件,这两个字符串在该文件中的不同行。一个包含以下内容的文件:

blah blah..
blah blah..
blah abc blah
blah blah..
blah blah..
blah blah..
blah efg blah blah
blah blah..
blah blah..

应该匹配。


当前回答

如果你需要两个单词彼此接近,例如不超过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命令。

其他回答

你至少有几个选择

DOTALL方法

用(?s) DOTALL the。包含\n的字符 你也可以使用一个超前(?=\n)——不会在匹配中被捕获

example-text:

true
match me

false
match me one

false
match me two

true
match me three
third line!!
{BLANK_LINE}

命令:

grep -Pozi '(?s)true.+?\n(?=\n)' example-text

-p用于perl正则表达式

-o只匹配模式,而不是整行

-z允许换行

-i不区分大小写

输出:

true                                                  
match me                                              
true                                                  
match me three                                        
third line!!

注:

- +? makes modifier non-greedy so matches shortest string instead of largest (prevents from returning one match containing entire text)

你可以使用老式的O.G.手动方法,使用\n

命令:

grep -Pozi 'true(.|\n)+?\n(?=\n)'

输出:

true                                                  
match me                                              
true                                                  
match me three                                        
third line!!

下面是一个受到这个答案启发的解决方案:

如果'abc'和'efg'可以在同一行: Grep -zl 'abc。*efg' <您的文件列表> 如果'abc'和'efg'必须在不同的行上: grep -Pzl '(?s)abc.*\n.;*efg' <您的文件列表>

参数:

-P使用perl兼容的正则表达式。 将输入视为一组行,每一行以0字节结束,而不是换行符。例如,grep将输入视为一行。注意,如果你不使用-l,它将显示匹配后的NUL字符,见注释。 -l list只匹配文件名。 (?s)激活PCRE_DOTALL,这意味着'。'查找任何字符或换行符。

Grep是这种操作的笨拙工具。

在大多数现代Linux系统中都可以找到pcregrep,可以用作

pcregrep -M  'abc.*(\n|.)*efg' test.txt

where -M,——multiline允许模式匹配多行

还有一个更新的pcre2grep。两者都是由PCRE项目提供的。

pcre2grep可以通过Mac Ports作为pcre2端口的一部分用于Mac OS X:

% sudo port install pcre2 

并通过Homebrew为:

% brew install pcre

或者pcre2

% brew install pcre2

pcre2grep在Linux (Ubuntu 18.04+)上也可用

$ sudo apt install pcre2-utils # PCRE2
$ sudo apt install pcregrep    # Older PCRE
#!/bin/bash
shopt -s nullglob
for file in *
do
 r=$(awk '/abc/{f=1}/efg/{g=1;exit}END{print g&&f ?1:0}' file)
 if [ "$r" -eq 1 ];then
   echo "Found pattern in $file"
 else
   echo "not found"
 fi
done

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

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

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