我想使用 sed 命令获得更好的性能:
sed -n '/<html>/,/<\/html>/p' filename > output
该命令运行良好。但是我在一个文件中有多个 html 标签。我想在 HTML 标签的第一次出现之间提取内容,
我想使用 sed 命令获得更好的性能:
sed -n '/<html>/,/<\/html>/p' filename > output
该命令运行良好。但是我在一个文件中有多个 html 标签。我想在 HTML 标签的第一次出现之间提取内容,
这应该给你第一个<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 中。
因此,假设您要提取 <html> .. </html> 分隔符之间的内容,但您的文本文件中有多组分隔符。例如;
blah <html> this </html> blah <html> that </html> blah
blah
<html>
the_other </html>
应该返回
this that the_other
(笔记:
如果只有一对 <html> .. </html> 分隔符,原始海报提供的 sed 脚本可以正常工作。问题是同一个文件中有多个副本。
顺便说一句,这不是“解析 HTML”。使用正则表达式的问题是真正的正则表达式不能匹配嵌套标签,你不能嵌套 <html> 标签。)
这是我的尝试(使用 perl):
perl -e '$/=""; $_=<>; while (m#\G(.*?)<html>(.*?)</html>#gs) {print "<html>$2</html>\n";}' filename > output
我相信这可以满足您的要求。
(解释:
perl -e 'command'
运行 perl 脚本command
。$/=""
清除记录分隔符,因此 Perl 将整个文件视为一个“行”。$_=<>
将整个文件读入变量$_
.while ($condition) {print "$stuff";}
是不言自明的。m#$pattern#gs
全局匹配 $pattern (the g
); s
允许.
匹配任何字符,包括\n
. 如果将匹配添加前缀m
,则可以使用任何分隔符代替/
; 我用过#
。\G(.*?)<html>(.*?)</html>
中,\G
表示最近一次全局匹配的位置,两者.*?
匹配任意字符串(?
使得匹配非贪婪,所以我们取最短匹配而不是最长匹配),并且...( )
捕获我们在变量$1
and中使用的字符串,因此我们可以在...$2
之间复制字符串,就像在我们的 print 语句中一样。)<html>
</html>
$2
将您的文件视为文本文件。如果需要解析 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
使用awk
:
awk 'NR==1,/<\/html>/' input_file
这个单行将从文件的开头开始到第一个结束 html 块。如果在第一个 html 块开始之前有行,它们也会被打印出来。
使用 grep -o 仅提取第一<html>...</html>
对
grep -oP "^.+?</html>" filename |head -1 | sed -n '/<html>/,/<\/html>/p' > output
然而,就像sed
它本身一样,这只有在<html></html>
标签总是在同一行时才有效。