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

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

应该匹配。


当前回答

我不知道如何用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。

其他回答

文件模式*.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。

随着几个月前ugrep的发布:

ugrep 'abc(\n|.)+?efg'

这个工具是高度优化的速度。它也是GNU/BSD/PCRE-grep兼容的。

注意我们应该使用惰性重复+?,除非您想将所有efg行匹配在一起,直到文件中的最后一个efg。

下面是一种连续使用两个grep的方法:

egrep -o 'abc|efg' $file | grep -A1 abc | grep efg | wc -l

返回0或正整数。

egrep -o(只显示匹配,技巧:同一行上的多个匹配会产生多行输出,就好像它们在不同的行上一样)

grep -A1 abc(打印abc及其后面的行) Grep efg | wc -l(在ABC之后的相同或后面的行中发现的efg行数为0-n,结果可用于'if") 如果需要模式匹配,可以将Grep更改为egrep等

如果可以使用Perl,就可以很容易地做到这一点。

perl -ne 'if (/abc/) { $abc = 1; next }; print "Found in $ARGV\n" if ($abc && /efg/); }' yourfilename.txt

您也可以使用单个正则表达式来实现这一点,但这涉及到将文件的整个内容放入单个字符串中,对于大型文件,这可能会占用太多内存。 为了完整起见,下面是该方法:

perl -e '@lines = <>; $content = join("", @lines); print "Found in $ARGV\n" if ($content =~ /abc.*efg/s);' yourfilename.txt

我不确定是否可以使用grep,但sed使它非常简单:

sed -e '/abc/,/efg/!d' [file-with-content]