Regex Grep/Sed在具有多行的两个标记之间
我有很多文件需要从中获取信息 我的文件示例: 第一个文件内容:Regex Grep/Sed在具有多行的两个标记之间,regex,linux,bash,sed,Regex,Linux,Bash,Sed,我有很多文件需要从中获取信息 我的文件示例: 第一个文件内容: “测试此信息我需要grep” 及 第二个文件内容(有两行): “测试此信息= 我也需要格雷普“ 在结果中,我需要grep这个文本:从第一个文件-“此信息我需要grep”和从第二个文件-“此信息=我也需要grep” 在第一个文件中,我使用: grep -o 'test .*</singleline>' * | sed -e 's/test \(.*\)<\/singleline>/\1/' grep-o't
“测试此信息我需要grep”
及
第二个文件内容(有两行):
“测试此信息=
我也需要格雷普“
在结果中,我需要grep这个文本:从第一个文件-“此信息我需要grep”和从第二个文件-“此信息=我也需要grep”
在第一个文件中,我使用:
grep -o 'test .*</singleline>' * | sed -e 's/test \(.*\)<\/singleline>/\1/'
grep-o'test.*|sed-e's/test\(.*)/\1/'
并成功获取“此信息我需要grep”,但我无法使用相同的命令从第二个文件获取信息
请帮助重写命令或编写其他命令。我将使用可以匹配多行正则表达式的
pcregremp
:
pcregrep -Mo 'test \K((?s).)*?(?=</singleline>)' filename
pcregrep-Mo'test\K((?)*?(?=)文件名
诀窍是:
允许-M
在多行上匹配pcregrep
使其仅打印匹配项-o
丢弃前面的部分\K
是一个前瞻性术语,当(且仅当)空字符串后跟(?=)
时,它与空字符串匹配,并且
非贪婪地匹配任何字符,也就是说,如果文件中多次出现((?)*?
,它将匹配到最近的字符,而不是最远的字符。如果不需要,请卸下?
在本地为术语启用(?s)
选项,以使s
匹配其中的换行符;默认情况下,它不会这样做
感谢@casimirithippolyte指出了
((?)
替代(.|\n)
,或者,如果您坚持使用grep
,您可以:
grep -Pzo 'test(\n|.)*(?=</singleline>)' test.txt
grep-Pzo'test(\n |)*(?=)'test.txt
要理解每个标志的含义,请使用grep--help
:
,--perl regexp 模式是一个Perl正则表达式-p
,仅匹配 仅显示线条匹配图案的一部分-o
,--空数据 数据行以0字节结束,而不是换行-z
=
结尾的行表示(在\n
之前)
由于在随后的评论中,您还表示希望将每个匹配打印为一行,因此我建议采用以下两种方法:
- 使用
删除软换行符awk
- 然后对结果使用
grep
awk'/=$/{printf“%s”,substr($0,1,length($0)-2);下一个}1'文件|
grep-Po测试。*?(?=)'
对于非贪婪量词,*?
,以及Wintermute和积极的前瞻性断言,(?=…)
,帽子的一角
不是说awk
命令删除了以=
结尾的行(以及换行符);将substr
调用替换为仅$0
即可保留它
由于感兴趣的字符串首先转换回其原始单线表示形式:
- 比赛以原始形式打印
- 您可以使用常规(GNU)
进行逐行匹配;将此与grep
- 需要一次读取整个文件,如。
请注意,在撰写本文时,他的答案中必须将
替换为*
,才能在具有多个匹配项的文件中正确工作*?
- 需要安装另一个实用程序,
,如中所示pcregrep
- 此外,必须将匹配项清理为单行(这是您最初没有作为要求声明的)
- 需要一次读取整个文件,如。
pcregremp
,您可以通过sudo apt get install pcregremp
获得它。对于@wintermute,回答和解释都很好。您应该避免这种丑陋(且低效)的构造(.|\n)*?
,它更适合posix引擎(非贪婪量词除外)。例如,你可以用([^@casimirithippolyte,谢谢,这是个好主意。我把(?)
放进去;我认为排除sed'1h;1!H;$!d;x;s/\n//g'
是一种我所知道的所有sed都可以使用的方法(BSD sed,正如在*BSD和MacOS X上发现的那样,与许多其他多行sed方法相比是笨拙的)。另一种方法是在slurp模式Perl中完成整个过程:Perl-0777-nE'($)=m/test\K((?)*(?=)/;s/\n//g;说“filename
”--“注意,slurp模式Perl(如书面形式)将仅隔离第一个匹配项。如果文件中有两个可能的匹配项,我不知道您希望发生什么。巧妙的技巧;为了澄清:通过使用-z
将NUL指定为“行”分隔符,您可以一次有效地读取整个输入,从而允许跨行匹配。我建议使用非贪婪量词(*?
而不是*
),如@Wintermute的回答所示。问题是,如果将匹配重定向到文件grep-Pzo
的情况下,在文件末尾写入值为0
的字节。那么这0-byte
会导致diff
将文本文件解释为二进制文件。如何防止在我们重编的文件末尾写入0-byte
直肠?
grep -Pzo 'test(\n|.)*(?=</singleline>)' test.txt