grep或sed - 需要提取特定文本

时间:2013-05-24 23:33:40

标签: regex shell sed grep

如何仅提取匹配文本的子字符串。

我有一个包含多行的XML文件。然而,这就是我所关注的。

<url>/localhost/index.html</url>

我试过

cat file.txt | grep -o '<url>.*</url>' 

它给了我整条线。我只想打印/localhost/index.html。有没有其他我可以使用的选项,就像我在Python中所知,你可以将正则表达式分组到子组中并选择你想要打印的那个。

3 个答案:

答案 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