我有以下文件:
<head>
<title>this is a title</title>
<style>
here goes a style sheet
</style>
</head>
我需要使用<title>
来从中剥离元素sed
。目前我使用
cat test.html | sed 's/<title>.*<\/title>//'
并且它可以工作,但我不明白如何去掉空白行。也就是说,目前输出是
<head>
<style>
here goes a style sheet
</style>
</head>
但我希望如此
<head>
<style>
here goes a style sheet
</style>
</head>
为此,我尝试使用 GNU 和 BSD添加\s*
或\n*
sed
cat test.html | sed 's/<title>.*<\/title>\s*//'
cat test.html | sed 's/<title>.*<\/title>\n*//'
但这没有帮助。我做错了什么?
编辑:此<title>
行不必单独成行。也就是说,有时整个文件可能只有一行:
<head><title>this is a title</title><style>here goes a style sheet</style></head>
在这种情况下,期望的输出是
<head><style>here goes a style sheet</style></head>
命令
s
修改sed
行。要删除行,请使用命令d
。假设title
节点(包括其值)在输入文档中的一行上,您可以使用(用作
,
要删除的地址的替代分隔符。)但是使用以下方法会更快(不用思考)
grep -v
:但是,由于这是一个 XML 文件,因此我将使用能够理解这种结构化文档格式的工具。下面的代码使用
xmlstarlet
和 ,它不关心title
节点的值是否包含换行符,也不关心节点本身是否包含属性。它只会删除title
顶级head
节点下面的节点,而不会删除其他节点,而sed
和grep
不知道文档的结构,会盲目删除与您指定的模式匹配的任何行。如果不想添加 XML 声明,请使用
xmlstarlet
其-O
(或)选项。您还可以使用(或)--omit-decl
进行“就地”编辑。-L
--inplace
使用这些选项,并使用缩短的语法:
如果文档是 HTML 文档(不是 XHTML,后者已经是 XML),您可以
xmlstarlet
在编辑之前使用以下命令将其转换为 XML:例如
请注意,我们需要使用路径
/html/head/title
而不是更短的路径/head/title
,因为head
节点必须包含在html
节点中才能成为有效的 XHTML 文件(如果它从一开始就是 XML 文件,我们显然可以完全跳过这一步)。如果你没有并且无法安装 XML 感知工具,那么使用任何 awk(强制性的 POSIX 工具,存在于所有 Unix 机器上)并且每次只将 1 行读入内存,假设你的标题字符串始终在一行上,并且不会
<title>
出现</title>
在该行的其他上下文中,也不会在其他行的其他上下文中一起出现,你所需要的只是:上面只是说“删除标题字符串(
sub("<title>.*</title>","")
)并且如果结果行是空(!NF
)则不要打印它(next
)”。为了演示,使用根据 OP 的问题和答案中的示例创建的输入文件:
我们可以看到标题字符串被删除,但没有留下空行,后续
<style>
行的缩进也没有发生变化:关于:
在您使用的第一个脚本中,
\s
它是 sed 的非 POSIX GNU 扩展,是 的简写[[:space:]]
,在这两个脚本中,您都试图匹配换行符,但 sed 每次将输入的每一行读入其缓冲区进行操作,因此缓冲区中没有换行符供 sed 与您的正则表达式匹配。在 sed 中有多种方法可以处理该问题(GNU sed-z
一次将整个文件读入内存,或某些 sed 指令将行附加到“保留空间”,或基于替换结果的复合操作块),但使用 awk 更清晰、更简单、更高效、更便携。我发现的一个解决方案是使用以下
-z
选项:请注意,它目前仅受 GNU 支持
sed
。(由于我使用的是 macOS,它随 BSD 实用程序一起提供,因此我仍在寻找其他东西。)编辑:为了解决 Kusalananda 提到的问题,我们需要使
sed
匹配不贪婪。这可以通过以下“技巧”实现:test2.html
:那么您不需要提防
</title>
。