如何仅提取匹配文本的子字符串。
我有一个包含多行的XML文件。然而,这就是我所关注的。
<url>/localhost/index.html</url>
我试过
cat file.txt | grep -o '<url>.*</url>'
它给了我整条线。我只想打印/localhost/index.html
。有没有其他我可以使用的选项,就像我在Python中所知,你可以将正则表达式分组到子组中并选择你想要打印的那个。
答案 0 :(得分:6)
如果您的grep
不支持-P
(请参阅ruakh's answer),您可以使用sed
来执行此操作:
sed -n 's|.*<url>\(.*\)</url>.*|\1|p'
答案 1 :(得分:2)
如果您的grep
版本支持-P
标记(对于Perl兼容的正则表达式),则可以使用lookaround:
grep -Po '(?<=<url>).*(?=</url>)' file.txt
答案 2 :(得分:2)
我会使用sed
:
sed -n 's%.*<url>\(.*\)</url>.*%\1%p'
-n
选项会关闭默认打印。 substitute命令匹配单行上的<url>
和</url>
标记,捕获其间的内容并包含匹配中的前导和尾随材质。替换是捕获的材料,p
表示打印。我在%
中使用了s%%%
而不是s///
,因为/
出现在正则表达式中。另一种方法是使用斜杠并使用反斜杠转义正则表达式中的斜杠。
Perl也可行且简单:
perl -n -e 'print if s%.*<url>(.*)</url>.*%\1%'
-n
创建一个REPL,但默认情况下不打印;仅当替代操作进行替换时才会触发print
。
这个稍微复杂的Perl脚本正确处理单行上的多个<url>...</url>
条目:
perl -n -e 'print "$1\n" while (s%.*?<url>(.*?)</url>%%)'
它使用非贪婪的正则表达式(.*?
)来避免吃太多信息。当替换操作检测并删除带有可选前置垃圾的<url>...</url>
时,代码会在URL标记之间打印匹配的部分,后跟换行符。
鉴于数据:
xyz <url>/localhost/index1.html</url> pqr
xyz <url>/localhost/index2.html</url> abc <url>/localhost/index3.html</url> pqr
<url>/localhost/index4.html</url>
<url>/localhost/index5.html</url><url>/localhost/index6.html</url>
xyz <url>/localhost/index7.html</url> abc <url>/localhost/index3.html</url> xyz <url>/localhost/index9.html</url> abc <url>/localhost/index0.html</url> pqr
最后一个Perl脚本产生:
/localhost/index1.html
/localhost/index2.html
/localhost/index3.html
/localhost/index4.html
/localhost/index5.html
/localhost/index6.html
/localhost/index7.html
/localhost/index3.html
/localhost/index9.html
/localhost/index0.html