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

  • -p
    ,--perl regexp

    模式是一个Perl正则表达式

  • -o
    ,仅匹配

    仅显示线条匹配图案的一部分

  • -z
    ,--空数据

    数据行以0字节结束,而不是换行


看起来您正在解析引用的可打印编码文本,其中“软”换行符(固定线宽格式的产物)用一个以
=
结尾的行表示(在
\n
之前)

由于在随后的评论中,您还表示希望将每个匹配打印为一行,因此我建议采用以下两种方法:

  • 使用
    awk
    删除软换行符
  • 然后对结果使用
    grep
awk'/=$/{printf“%s”,substr($0,1,length($0)-2);下一个}1'文件|
grep-Po测试。*?(?=)'
对于非贪婪量词,
*?
,以及Wintermute和积极的前瞻性断言,
(?=…)
,帽子的一角

不是说
awk
命令删除了以
=
结尾的行(以及换行符);将
substr
调用替换为仅
$0
即可保留它

由于感兴趣的字符串首先转换回其原始单线表示形式:

  • 比赛以原始形式打印
  • 您可以使用常规(GNU)
    grep
    进行逐行匹配;将此与
    • 需要一次读取整个文件,如。
      请注意,在撰写本文时,他的答案中必须将
      *
      替换为
      *?
      ,才能在具有多个匹配项的文件中正确工作
    • 需要安装另一个实用程序,
      pcregrep
      ,如中所示
    • 此外,必须将匹配项清理为单行(这是您最初没有作为要求声明的)

这是因为grep是行匹配的,所以您必须使用-n选项和awk来获取您想要的OP信息:如果您没有
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