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 行。当然这取决于你的文件和单词组合。但对我来说,这是最快且可靠的解决方案。
这是使用 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) 作为记录分隔符。在没有连续换行符的情况下,会立即读取(吞咽)整个文件。
难道不是大文件做到这一点,将整个文件加载到内存中,并且可能是一个问题。
假设我们的文件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)