我需要打印两个模式之间的文本,而不需要记住它们的位置,因为它们是在文件中随机找到的。在同一行或不在同一行或它们之间出现文本
模式是:<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
因为在原始文件中我们有新行。当然,如果您愿意的话,您可以通过管道输出来删除空格(使用tr
或sed
其他方式),但正如我所说:在现实生活中的示例中,您可能会遇到更多意想不到的结果。
答案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 解决方案是将模式 和 转换为文件中其他任何地方未使用的其他两个字符。这会将问题转换为在两个单个字符之间进行提取的一般问题。
首先,将每个模式转换为单个字符:
sed 'H;$!d;x; s##^A#g; s##^B#g;'文件
假设您为每个输入了Ctrl- V Ctrl- ,对于 也输入了类似的命令。A
^A
^B
最初
H;$!d;x;
是捕获模式空间中的整个文件。这意味着:- 守住每一行
- 擦除模式空间(并返回到开头)
d
- 如果这是不是最后一行
$!
- 获取存储在保留空间中的所有行
x
。 (可能是g
,但 x 需要更少的内存,因为整个文件不会从保留空间复制到模式空间)。
提取两个单个字符(假设
x
和y
这里)之间的模式的一般过程是: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