grep / Sed之间的两个标签与多行

我有很多文件,我需要从中获取信息。

我的文件示例:

第一个文件内容:

"test This info i need grep</singleline>"

第二个文件内容(两行):

 "test This info= i need grep too</singleline>" 

在结果我需要grep这个文本:从第一个文件 – “这个信息我需要grep”和从第二个文件 – “这个信息=我需要grep太”

在我使用的第一个文件中:

 grep -o 'test .*</singleline>' * | sed -e 's/test \(.*\)<\/singleline>/\1/' 

并成功地得到“这个信息我需要grep”,但我不能从第二个文件通过使用相同的命令获取信息。

请帮助改写命令或写另一个。

我会使用pcregrep ,它可以匹配多行的正则表达式:

 pcregrep -Mo 'test \K((?s).)*?(?=</singleline>)' filename 

这些技巧是:

  • -M允许pcregrep匹配多个行,
  • -o使它只打印匹配,
  • \K扔掉之前的比赛的一部分,
  • (?=</singleline>)是一个与空字符串匹配的前瞻性术语,如果(且仅当)后面紧跟</singleline> ,则
  • ((?s).)*? 以非贪婪的方式匹配任何字符,也就是说,如果文件中有多个</singleline>出现,它将匹配到最近而不是最远。 如果不需要,请删除?(?s)在本地启用该选项. 匹配换行符; 它不会默认这样做。

感谢@CasimiretHippolyte指出((?s).)替代(.|\n)

或者,如果你坚持使用grep ,你可以:

 grep -Pzo 'test(\n|.)*(?=</singleline>)' test.txt 

要理解每个标志的含义,请使用grep --help

  • -P ,–perl-regexp

    PATTERN是一个Perl正则表达式

  • -o , – 唯一匹配

    仅显示匹配PATTERN的行的部分

  • -z ,–null-data

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

它看起来像解析quoted-printable编码文本,其中一个“软”换行符(一个是来自固定行宽格​​式化的工件)用line-terminating = (直接在\n之前)表示。

由于在稍后的评论中你也表达了打印每一场比赛的愿望,所以我建议以下两个方面的评价:

  • 使用awk删除软线断点
  • 然后对结果使用grep
 awk '/=$/ { printf "%s", substr($0, 1, length($0)-2); next } 1' file | grep -Po 'test .*?(?=</singleline>)' 

Wintermute对非贪婪量词的有用答案的提示, *? ,而Wintermute和Maroun Maroun对积极的预见性断言(?=...)提供了有用的答案 。

不是说awk命令删除行结尾= (与新行一起); 用$0替换substr调用来保留它。

由于感兴趣的字符串首先被转换回原来的单行表示:

  • 比赛打印的原始形式。
  • 您可以使用常规(GNU) grep逐行匹配; 与此形成对比
    • 需要马上阅读整个文件,就像Maroun Maroun的有用答案一样 。
      请注意,在撰写本文时, *必须替换为*? 在他的工作正确工作的答案在多个匹配的文件。
    • 需要安装另一个实用程序, pcregrep ,如Wintermute的有用答案 。
    • 此外,比赛将不得不被清理为单线(你最初没有说明的要求)。