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

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

应该匹配。


当前回答

文件模式*.sh对于防止目录被检查很重要。当然,一些测试也可以防止这种情况发生。

for f in *.sh
do
  a=$( grep -n -m1 abc $f )
  test -n "${a}" && z=$( grep -n efg $f | tail -n 1) || continue 
  (( ((${z/:*/}-${a/:*/})) > 0 )) && echo $f
done

The

grep -n -m1 abc $f 

搜索最大1个匹配项并返回(-n)行数。 如果找到一个匹配(test -n…),找到efg的最后一个匹配(找到所有,并使用tail -n 1取最后一个匹配)。

z=$( grep -n efg $f | tail -n 1)

其他的继续。

由于结果类似于18:foofile.sh String alf="abc";我们需要从“:”开始切到行尾。

((${z/:*/}-${a/:*/}))

如果第二个表达式的最后一个匹配超过了第一个表达式的第一个匹配,则应返回正结果。

然后我们报告文件名echo $f。

其他回答

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

awk一行程序:

awk '/abc/,/efg/' [file-with-content]

你至少有几个选择

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!!

文件模式*.sh对于防止目录被检查很重要。当然,一些测试也可以防止这种情况发生。

for f in *.sh
do
  a=$( grep -n -m1 abc $f )
  test -n "${a}" && z=$( grep -n efg $f | tail -n 1) || continue 
  (( ((${z/:*/}-${a/:*/})) > 0 )) && echo $f
done

The

grep -n -m1 abc $f 

搜索最大1个匹配项并返回(-n)行数。 如果找到一个匹配(test -n…),找到efg的最后一个匹配(找到所有,并使用tail -n 1取最后一个匹配)。

z=$( grep -n efg $f | tail -n 1)

其他的继续。

由于结果类似于18:foofile.sh String alf="abc";我们需要从“:”开始切到行尾。

((${z/:*/}-${a/:*/}))

如果第二个表达式的最后一个匹配超过了第一个表达式的第一个匹配,则应返回正结果。

然后我们报告文件名echo $f。

这个也能用吗?!

perl -lpne 'print $ARGV if /abc.*?efg/s' file_list

$ARGV包含从file_list读取当前文件时的文件名 /s修饰符跨换行搜索。