如何跨多行“grep”模式?

Jim*_*Jim 45 grep search regular-expression file-search

看来我在滥用grep/ egrep

我试图在多行中搜索字符串,但找不到匹配项,而我知道我要查找的内容应该匹配。最初我认为我的正则表达式是错误的,但我最终读到这些工具是按行运行的(而且我的正则表达式是如此微不足道,这不可能是问题)。

那么,应该使用哪种工具来跨多行搜索模式呢?

Jos*_* R. 41

这是sed一个可以grep跨多行为您提供类似行为的方法:

sed -n '/foo/{:start /bar/!{N;b start};/your_regex/p}' your_file
Run Code Online (Sandbox Code Playgroud)

这个怎么运作

  • -n 禁止打印每一行的默认行为
  • /foo/{}指示它匹配foo并执行波浪线内部与匹配线的操作。替换foo为图案的起始部分。
  • :start 是一个分支标签,帮助我们继续循环,直到找到正则表达式的结尾。
  • /bar/!{}将对不匹配的行执行波浪线中的内容bar。替换bar为模式的结束部分。
  • N将下一行附加到活动缓冲区(sed称之为模式空间)
  • b start将无条件地分支到start我们之前创建的标签,以便只要模式空间不包含bar.
  • /your_regex/p如果匹配,则打印模式空间your_regex。您应该替换your_regex为要跨多行匹配的整个表达式。


pra*_*tri 23

我通常使用一个名为的工具pcregrep,该工具可以使用yum或安装在大多数 linux 风格中apt

例如。

假设您有一个以testfile内容命名的文件

abc blah
blah blah
def blah
blah blah
Run Code Online (Sandbox Code Playgroud)

您可以运行以下命令:

$ pcregrep -M  'abc.*(\n|.)*def' testfile
Run Code Online (Sandbox Code Playgroud)

跨多行进行模式匹配。

此外,您也可以执行相同的操作sed

$ sed -e '/abc/,/def/!d' testfile
Run Code Online (Sandbox Code Playgroud)


Avi*_*Raj 13

只需一个支持Perl-regexp参数的普通 grepP就可以完成这项工作。

$ echo 'abc blah
blah blah
def blah
blah blah' | grep -oPz  '(?s)abc.*?def'
abc blah
blah blah
def
Run Code Online (Sandbox Code Playgroud)

(?s) 称为 DOTALL 修饰符,它使正则表达式中的点不仅匹配字符,还匹配换行符。


小智 8

我使用 grep 和 -A 选项与另一个 grep 解决了这个问题。

grep first_line_word -A 1 testfile | grep second_line_word
Run Code Online (Sandbox Code Playgroud)

-A 1 选项在找到的行之后打印 1 行。当然这取决于你的文件和单词组合。但对我来说,这是最快且可靠的解决方案。


ter*_*don 7

这是使用 Perl 的一种更简单的方法:

perl -e '$f=join("",<>); print $& if $f=~/foo\nbar.*\n/m' file
Run Code Online (Sandbox Code Playgroud)

或者(既然 JosephR走这sed条路,我就无耻地窃取他的建议

perl -n000e 'print $& while /^foo.*\nbar.*\n/mg' file
Run Code Online (Sandbox Code Playgroud)

解释

$f=join("",<>);:这会读取整个文件并将其内容(换行符和所有内容)保存到变量中$f。然后我们尝试 match foo\nbar.*\n,如果匹配则打印它(特殊变量$&保存找到的最后一个匹配项)。的///m需要,使整个新行的正则表达式匹配。

-0设置输入记录分隔符。将此设置为00激活“段落模式”,其中 Perl 将使用连续的换行符 ( \n\n) 作为记录分隔符。在没有连续换行符的情况下,会立即读取(吞咽)整个文件。

警告:

难道不是大文件做到这一点,将整个文件加载到内存中,并且可能是一个问题。


Nic*_*tel 6

假设我们的文件test.txt包含:

blabla
blabla
foo
here
is the
text
to keep between the 2 patterns
bar
blabla
blabla
Run Code Online (Sandbox Code Playgroud)

可以使用以下代码:

sed -n '/foo/,/bar/p' test.txt
Run Code Online (Sandbox Code Playgroud)

对于以下输出:

foo
here
is the
text
to keep between the 2 patterns
bar
Run Code Online (Sandbox Code Playgroud)