2

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

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

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

4

5 回答 5

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 中。

于 2013-05-29T12:06:29.267 回答
1

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

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

应该返回

this that the_other

(笔记:

  1. 如果只有一对 <html> .. </html> 分隔符,原始海报提供的 sed 脚本可以正常工作。问题是同一个文件中有多个副本。

  2. 顺便说一句,这不是“解析 HTML”。使用正则表达式的问题是真正的正则表达式不能匹配嵌套标签,你不能嵌套 <html> 标签。)

这是我的尝试(使用 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 (the g); s允许.匹配任何字符,包括\n. 如果将匹配添加前缀m,则可以使用任何分隔符代替/; 我用过#
  6. 在 pattern\G(.*?)<html>(.*?)</html>中,\G表示最近一次全局匹配的位置,两者.*?匹配任意字符串(?使得匹配非贪婪,所以我们取最短匹配而不是最长匹配),并且...
  7. ...( )捕获我们在变量$1and中使用的字符串,因此我们可以在...$2之间复制字符串,就像在我们的 print 语句中一样。)<html></html>$2
于 2013-05-29T13:36:28.280 回答
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
于 2013-05-29T11:28:24.020 回答
0

使用awk

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

笔记:

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

于 2013-05-29T12:39:55.327 回答
0

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

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

然而,就像sed它本身一样,这只有在<html></html>标签总是在同一行时才有效。

于 2013-05-29T11:48:37.167 回答