我想找到按顺序有"abc"和"efg"的文件,这两个字符串在该文件的不同行上.例如:包含内容的文件:
blah blah..
blah blah..
blah abc blah
blah blah..
blah blah..
blah blah..
blah efg blah blah
blah blah..
blah blah..
Run Code Online (Sandbox Code Playgroud)
应该匹配.
rin*_*rer 203
Grep不足以进行此操作.
在大多数现代Linux系统中都可以使用pcregrep作为
pcregrep -M 'abc.*(\n|.)*efg' test.txt
Run Code Online (Sandbox Code Playgroud)
还有一个更新的pcre2grep.两者都是由PCRE项目提供的.
pcre2grep可通过Mac端口作为端口的一部分用于Mac OS X pcre2:
% sudo port install pcre2
Run Code Online (Sandbox Code Playgroud)
并通过Homebrew:
% brew install pcre
Run Code Online (Sandbox Code Playgroud)
或者是pcre2
% brew install pcre2
Run Code Online (Sandbox Code Playgroud)
小智 110
我不确定grep是否可行,但是sed使它非常简单:
sed -e '/abc/,/efg/!d' [file-with-content]
Run Code Online (Sandbox Code Playgroud)
att*_*tti 77
这是一个灵感来自这个答案的解决方案:
如果'abc'和'efg'可以在同一行:
grep -zl 'abc.*efg' <your list of files>
Run Code Online (Sandbox Code Playgroud)如果'abc'和'efg'必须在不同的行上:
grep -Pzl '(?s)abc.*\n.*efg' <your list of files>
Run Code Online (Sandbox Code Playgroud)PARAMS:
-z将输入视为一组行,每行以零字节而不是换行符结束.即grep威胁输入作为一个大的线.
-l 打印通常从中输出的每个输入文件的名称.
(?s)激活PCRE_DOTALL,这意味着'.' 找到任何字符或换行符.
小智 32
sed应该足够像上面提到的海报LJ,
而不是!d你可以简单地使用p来打印:
sed -n '/abc/,/efg/p' file
Run Code Online (Sandbox Code Playgroud)
sag*_*age 13
我非常依赖pcregrep,但是对于更新的grep,你不需要为它的许多功能安装pcregrep.只是用grep -P.
在OP的问题的例子中,我认为以下选项很好地工作,第二个最佳匹配我如何理解这个问题:
grep -Pzo "abc(.|\n)*efg" /tmp/tes*
grep -Pzl "abc(.|\n)*efg" /tmp/tes*
Run Code Online (Sandbox Code Playgroud)
我将文本复制为/ 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
Run Code Online (Sandbox Code Playgroud)
要确定您的版本是否足够新,请运行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.
Run Code Online (Sandbox Code Playgroud)
那是来自GNU grep 2.10.
g.r*_*ket 10
这可以通过首先使用tr用其他字符替换换行来轻松完成:
tr '\n' '\a' | grep -o 'abc.*def' | tr '\a' '\n'
Run Code Online (Sandbox Code Playgroud)
在这里,我使用警报字符\a(ASCII 7)代替换行符.这几乎从未在您的文本中找到,并且grep可以与a .匹配,或者与其特定匹配\a.
如果你可以使用Perl,你可以很容易地做到这一点.
perl -ne 'if (/abc/) { $abc = 1; next }; print "Found in $ARGV\n" if ($abc && /efg/); }' yourfilename.txt
Run Code Online (Sandbox Code Playgroud)
您也可以使用单个正则表达式执行此操作,但这涉及将文件的全部内容转换为单个字符串,这可能最终会占用大文件的太多内存.为了完整性,这是方法:
perl -e '@lines = <>; $content = join("", @lines); print "Found in $ARGV\n" if ($content =~ /abc.*efg/s);' yourfilename.txt
Run Code Online (Sandbox Code Playgroud)
小智 6
awk一线:
awk '/abc/,/efg/' [file-with-content]
Run Code Online (Sandbox Code Playgroud)
我不知道用grep怎么做,但是我会用awk做这样的事情:
awk '/abc/{ln1=NR} /efg/{ln2=NR} END{if(ln1 && ln2 && ln1 < ln2){print "found"}else{print "not found"}}' foo
Run Code Online (Sandbox Code Playgroud)
但是,你需要注意如何做到这一点.你想要正则表达式匹配子字符串或整个单词吗?根据需要添加\ w标签.此外,虽然这严格符合您所说的示例,但在ecg之后第二次出现abc时,它并不能正常工作.如果你想处理它,在/ abc/case等中添加一个if.
小智 5
如果您愿意使用上下文,可以通过键入来实现
grep -A 500 abc test.txt | grep -B 500 efg
Run Code Online (Sandbox Code Playgroud)
这将显示“abc”和“efg”之间的所有内容,只要它们彼此相距在 500 行以内。