sed

sed

我需要打印两个模式之间的文本,而不需要记住它们的位置,因为它们是在文件中随机找到的。在同一行或不在同一行或它们之间出现文本

模式是:<abc></abc>

例子 :

aslkdjas<abc>aaaa</abc><abc>bbbb</abc>sdkljasdl<abc>
cccc
dddd</abc>ieurwioeru<abc>eeee</abc>asdasd

我需要如下输出或以逗号分隔此文件中发生的任何情况,以显示两个模式之间的值:

aaaa
bbbb
cccc
dddd
eeee

答案1

我不建议使用文本处理工具解析任何功能代码。它们只是为了解析人类语言而设计的,迟早你会遇到无法解决的问题。使用专用工具(html 解释器、c++ 编译器等)

话虽如此,在这种情况下你可以尝试pcregrep

pcregrep -Mo '<abc>\K(.|\n)*?(?=</abc>)' file

结果是

aaaa
bbbb

cccc
dddd
eeee

bbbb是的,在和之间有新行,cccc因为在原始文件中我们有新行。当然,如果您愿意的话,您可以通过管道输出来删除空格(使用trsed其他方式),但正如我所说:在现实生活中的示例中,您可能会遇到更多意想不到的结果。

答案2

对于这个简单的情况,尝试

sed ':L1; N; $bL2; bL1; :L2; s#<abc>#^A#g; s#^[^^A]*^A##; s#</abc>[^^A]*^A#\n#g; s#</abc>.*$##; ' file
aaaa
bbbb

cccc
dddd
eeee

将所有行收集到模式空间中,用 替换前导模式^A,将 BOL 删除到第一个^A,用 替换模式之间的字符串<new line>,删除模式直到 EOL,打印。

答案3

sed

sed 解决方案是将模式 和 转换为文件中其他任何地方未使用的其他两个字符。这会将问题转换为在两个单个字符之间进行提取的一般问题。

  1. 首先,将每个模式转换为单个字符:

    sed 'H;$!d;x; s##^A#g; s##^B#g;'文件

    假设您为每个输入了Ctrl- V Ctrl- ,对于 也输入了类似的命令。A^A^B

    最初H;$!d;x;是捕获模式空间中的整个文件。这意味着:

    • 守住每一行
    • 擦除模式空间(并返回到开头)d
    • 如果这是不是最后一行$!
    • 获取存储在保留空间中的所有行x。 (可能是g,但 x 需要更少的内存,因为整个文件不会从保留空间复制到模式空间)。
  2. 提取两个单个字符(假设xy这里)之间的模式的一般过程是:

    sed 的#^[^x]X##; s#y[^y]$##; s#y[^x]*x#,#g;'

    那是:

    • 删除第一个 ( ^)之前的前导字符x
    • $删除最后一个 ( )之后的尾随字符y
    • 将 y 和 x 之间的字符转换为分隔符(,在本例中为逗号 ( ))。

全部一起:

$ sed 'H;$!d;x; s#<abc>#^A#g; s#</abc>#^B#g;' s#^[^^A]*^A##; s#^B[^^B]*$##; s#^B[^^A]*^A#,#g;' file
aaaa,bbbb,
cccc
dddd,eeee

grep

可以使用 (GNU) grep 来完成,但需要粘贴的帮助才能将逗号(仅)放在正确的位置:

$ grep -ozP '(?s)<abc>\K.*?(?=</abc>)' file | paste -zsd ','; echo
aaaa,bbbb,
cccc
dddd,eeee

相关内容