在Linux中,获取两个字符串之间的内容

时间:2013-05-29 11:03:25

标签: linux unix sed html-parsing

我想使用sed命令来获得更好的性能:

sed -n '/<html>/,/<\/html>/p' filename > output

此命令效果很好。 但是我在一个文件中有多个html标签。 我想在第一次出现的HTML标签之间提取内容   ,

5 个答案:

答案 0 :(得分:2)

这应该会给你第一个<html>阻止。

sed -n '/<html>/,/<\/html>/p;/<\/html>/q' file

示例:

kent$  cat file
<html>
a
</html>
<html>
b
</html>
<html>
c
</html>

kent$  sed -n '/<html>/,/<\/html>/p;/<\/html>/q' file
<html>
a
</html>
顺便说一句,我不认为OP正在解析html / xml。 html没有多个<html>标记。他的输入文件也可能不在xml中。

答案 1 :(得分:1)

因此,假设您要在&lt; html&gt;之间提取内容。 ..&lt; / html&gt;分隔符,但您的文本文件中有多组分隔符。例如;

blah <html> this </html> blah <html> that </html> blah
blah
<html>
the_other </html>

应该返回

this that the_other

(注:

  1. 如果只有一对&lt; html&gt;,那么原始海报给出的sed脚本可以正常工作。 ..&lt; / html&gt;分隔符。问题是同一文件中有多个副本。

  2. 顺便说一句,这不是“解析HTML”。使用正则表达式的问题在于,真正的正则表达式无法与嵌套标记匹配,并且您无法嵌套&lt; html&gt;标记)。

  3. 这是我对它的攻击(使用perl):

    perl -e '$/=""; $_=<>; while (m#\G(.*?)<html>(.*?)</html>#gs) {print "<html>$2</html>\n";}' filename > output
    

    我相信这可以做你想要的。

    (说明:

    1. perl -e 'command'运行perl脚本command
    2. $/=""清除记录分隔符,因此Perl将整个文件视为一个“行”。
    3. $_=<>将整个文件读入变量$_
    4. while ($condition) {print "$stuff";}不言自明。
    5. m#$pattern#gs全局匹配$ pattern(g); s允许.匹配任何字符,包括\n。如果您通过m为匹配添加前缀,则可以使用任何分隔符而不是/;我使用了#
    6. 在模式\G(.*?)<html>(.*?)</html>中,\G表示最近全局匹配的位置,两个.*?匹配任意字符串(?匹配非贪婪,所以我们采取最短的比赛而不是最长的比赛,并且......
    7. ... ( )捕获我们在变量$1$2中使用的字符串,因此我们可以在<html> ... {{1}之间复制字符串在我们的print语句中作为</html>。)

答案 2 :(得分:0)

将您的文件视为文本文件。如果需要解析HTML,则必须使用一些HTML解析器。

请注意,只有当您的内容标记为一行时,此代码才有效。

如果您只需要获取第一个标记的,此行可以提供帮助。

sed -n "/<html>/,/<\\/html>/{/>.*<\//{s/^[^>]*>\\([^<]*\\)<\\/.*/\1/gp;q}}" file.html

测试文件file.html

<html>
  <body>
    <ccc>test1</ccc><bbb>test2</bbb>
    <ccc1>test3</ccc1><bbb1>test4</bbb1>
  </body>
</html>

试验:

$ sed -n "/<html>/,/<\\/html>/{/>.*<\//{s/^[^>]*>\\([^<]*\\)<\\/.*/\1/gp;q}}" file.html
test1

按标签名称获取价值:

sed -n "/<html>/,/<\/html>/{/<$tag>/,/<\\$tag>/{s/.*$tag>\\([^<]*\\)<\\/$tag.*/\1/gp;q}}" file.html

试验:

$ tag=ccc
$ sed -n "/<html>/,/<\/html>/{/<$tag>/,/<\\$tag>/{s/.*$tag>\\([^<]*\\)<\\/$tag.*/\1/gp;q}}" 11
test1
$ tag=bbb
$ sed -n "/<html>/,/<\/html>/{/<$tag>/,/<\\$tag>/{s/.*$tag>\\([^<]*\\)<\\/$tag.*/\1/gp;q}}" 11
test2
$ tag=ccc1
$ sed -n "/<html>/,/<\/html>/{/<$tag>/,/<\\$tag>/{s/.*$tag>\\([^<]*\\)<\\/$tag.*/\1/gp;q}}" 11
test3
$ tag=bbb1
$ sed -n "/<html>/,/<\/html>/{/<$tag>/,/<\\$tag>/{s/.*$tag>\\([^<]*\\)<\\/$tag.*/\1/gp;q}}" 11
test4

答案 3 :(得分:0)

使用grep -o仅提取第一个<html>...</html>

grep -oP "^.+?</html>" filename |head -1 | sed -n '/<html>/,/<\/html>/p' > output

但是,就像sed本身一样,只有当<html></html>标记始终位于同一行时才会有效。

答案 4 :(得分:0)

使用awk

awk 'NR==1,/<\/html>/' input_file

注意:

这个单行将从文件的开头到第一个结束的html块开始。如果在第一个html块开始之前有行,它们也会被打印出来。