sed 替换图像的路径

sed 替换图像的路径

我需要替换目录中多个 xhtml 文件中图像的路径。文件头部分如下:

<?xml version="1.0" encoding="UTF-8"?>
<html xml:lang="en-us" lang="en-us" xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" xmlns:ns="http://www.w3.org/2001/10/synthesis">
<head>

尝试用命令来完成sed,但没有成功。可能是由于特定的 sed 版本,但不确定。我有GNU sed 4.4

original path:
<img src="/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg"
I need replace to:
<img src="graphics/line.jpg"

我试过

sed -i '.bak' 's/\/api\/v2\/epubs\/urn:orm:book:381260143574\/files/graphics/g' '*.xhtml'

它返回

sed: -e expression #1, char 1: unknown command: `.'

也尝试过

sed -i ' ' 's/\/api\/v2\/epubs\/urn:orm:book:381260143574\/files/graphics/g' '*.xhtml'
it return
sed: can't read s/\/api\/v2\/epubs\/urn:orm:book:381260143574\/files/graphics/g: No such file or directory
sed: can't read *.xhtml: No such file or directory

sed适合这个吗?

答案1

sed实用程序通常不适合编辑 XML 或 XHTML 文件。 XML 是一种结构化文档格式,不是面向行的。与许多标准 Unix 文本操作工具一样,该sed实用程序是面向行的,并且不需要额外的努力就无法处理 XML 实体的编码或解码之类的事情。

您的示例文档包含节点(已更正为包含/>在末尾)

<img src="/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg" />

由于节点内的空白(空格、制表符和换行符)是任意的,并且我们不知道节点的更多属性img或其顺序,因此使用sed.我们还必须确保除了节点src属性中的路径名之外,不要在其他任何地方替换路径名img

使用命令行 XML 解析器来执行此操作可能如下所示:

xmlstarlet ed   \
        -u '//img/@src[. = "/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg"]' \
        -v 'graphics/line.jpg' file.xhtml

我们使用xmlstarlet,一个相当知名的命令行 XML 解析器,如果属性的原始值为 ,则用字符串替换src每个节点的每个属性的值。imggraphics/line.jpg/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg

该命令将操作结果写入标准输出,但您可以在测试后使用其(或) 选项xmlstarlet进行就地编辑,以确保它看起来像您期望的那样工作。--inplace-L


如果您的img标签看起来像<img src="...">, 没有正确的结尾,那么您可以通过首先过滤您的 XHTML 文件来恢复此情况

xmlstarlet fo --recover --html file.xhtml

人们甚至可以设想表单上有一条管道

xmlstarlet fo --recover --html file.xhtml |
xmlstarlet ed   \
        -u '//img/@src[. = "/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg"]' \
        -v 'graphics/line.jpg'

如果您要处理的文件全部匹配模式./*.xhtml,即,如果它们具有.xhtml文件名后缀并且位于当前目录中,那么您将能够使用简单的 shell 循环使用上述命令中的任何一个来处理所有这些文件。

for name in ./*.xhtml; do
        xmlstarlet ed --inplace        \
                -u '//img/@src[. = "/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg"]'   \
                -v 'graphics/line.jpg' "$name"
done

请注意,这使用--inplace的选项xmlstarlet,该选项将修改文件而不进行备份。如果您在备份数据上运行此操作,那就最好了。

要对目录层次结构(即具有多个子目录的目录)中的所有 XHTML 文件运行上述命令,您可以使用find.

find . -type f -name '*.xhtml' -exec sh -c '
        for name do
                xmlstarlet ed --inplace        \
                        -u "//img/@src[. = \"/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg\"]" \
                        -v "graphics/line.jpg" "$name"
        done' sh {} +

答案2

如果它是 XHTML,您可以使用适当的 XML 编辑器对其进行编辑。这样做的优点是它不受文件布局更改的影响

首先,将示例修复为 XML(毕竟它是 XHTML 文档),

<img src="/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg"/>

如果您的源文档不是真正的 XHTML,您可以通过编程方式修复它

xmlstarlet format -H file.xhtml

您可以src使用以下命令编辑属性xmlstarlet

xmlstarlet edit --omit-decl --update '//img/@src' --value 'graphics/line.jpg' file.xhtml
<img src="hello"/>

或者通过组合这两个命令,

xmlstarlet fo -H file.xhtml 2>/dev/null |
    xmlstarlet ed -u '//img/@src' -v 'graphics/line.jpg'

准备好后,将结果放入临时文件中,然后用修改后的版本替换原始文件。 (或者将原始文件重命名为备份,并将其用作输入以创建具有原始名称的文件。)

如果您有多个<img/>元素,您可以为它们提供结构路径,而不仅仅是//img.如果您只想更改那些具有特定src属性值的属性,那也是可能的。但您的问题中确实没有足够的细节来有效地解决这些可能性。

答案3

尝试 :

sed -i.bak 's/\/api\/v2\/epubs\/urn:orm:book:381260143574\/files/graphics/g' *.xhtml


sed -i '.bak' --> sed -i.bak
'*.xhtml' --> *.xhtml

如果您不想转义斜杠,另一种选择是使用rpl.

在基于 Debian 的发行版上:

sudo apt install rpl

rpl -b "/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg" "graphics/line.jpg" *.xhtml

-b = backup

rpl 手册

答案4

你也可以试试这个sed。我没有包含该-i标志,因为它在测试时不合适。

sed -E 's|(img src=").[^"]*(/.*)|\1graphics\2|' input_file

这将对我们需要保留的匹配进行分组,同时排除我们不需要保留的匹配。

(.*=.)- 将所有内容分组,直到最后一次出现=

.[^"]*- 是排除的匹配。[^"]用于防止匹配到最后一个/并匹配到下一个"

(/.*)- 直到第二个到最后一个的所有内容/都已被排除,同时匹配之后的剩余模式。

\1graphics\2- 已创建两场小组赛,我们可以按任意顺序返回它们。由于graphics需要在之后进行硬编码=,我们可以在返回第一个分组匹配后立即插入它\1

|- 使用管道作为分隔符,因为数据本身包含“/”斜杠,这将与seds默认分隔符冲突。

输出

$ sed -E 's|(img src=").[^"]*(/.*)|\1graphics\2|' input_file
<img src="graphics/line.jpg"/>

相关内容