AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 670634
Accepted
minto
minto
Asked: 2021-09-26 13:33:25 +0800 CST2021-09-26 13:33:25 +0800 CST 2021-09-26 13:33:25 +0800 CST

sed 替换图像的路径

  • 772

我需要替换目录中多个 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适合这个吗?

bash shell-script
  • 6 6 个回答
  • 816 Views

6 个回答

  • Voted
  1. they
    2021-09-26T14:41:53+08:002021-09-26T14:41:53+08:00

    该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每个节点的每个属性的值替换img为字符串。graphics/line.jpg/api/v2/epubs/urn:orm:book:381260143574/files/line.jpg

    该命令将操作结果写入标准输出,但您可以在测试后使用它的(or ) 选项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'
    

    如果您要处理的文件都与 pattern 匹配./*.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 {} +
    
    • 5
  2. roaima
    2021-09-26T14:44:12+08:002021-09-26T14:44:12+08:00

    如果它是 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属性值的那些也是可能的。但是您的问题中没有足够的细节来有效地解决这些可能性。

    • 4
  3. Best Answer
    Gounou
    2021-09-26T14:04:59+08:002021-09-26T14:04:59+08:00

    尝试 :

    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手册

    • 1
  4. DonHolgo
    2021-09-26T14:08:21+08:002021-09-26T14:08:21+08:00

    该-i选项要求其值立即跟随,中间没有任何空格。所以你必须写-i.bak. 使用空格,sed将其解释为-i没有值(因此文件将就地更改)并.bak作为要运行的命令,因此是错误消息。您还需要删除引号*.html以允许外壳扩展通配符。

    (您的第二次尝试基本上有同样的问题,但这里的空格作为命令不会触发错误消息。)

    顺便说一句,您可以sed通过使用不同于的分隔符使您的命令更具可读性,/这样您就不需要转义字符串中的斜杠来替换,例如:

    sed -i.bak 's-/api/v2/epubs/urn:orm:book:381260143574/files-graphics-g' *.xhtml
    
    • 1
  5. HatLess
    2021-09-27T01:00:19+08:002021-09-27T01:00:19+08:00

    你也可以试试这个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"/>
    
    • 1
  6. bxm
    2021-09-27T00:58:43+08:002021-09-27T00:58:43+08:00

    肯定有强烈的反对使用sed这种东西的论据,其他人也提出了这些。

    但是,您可能无法使用提到的专用工具。因此,如果您的输入文件的结构可以适当地预测以允许sed工作,那么我会这样做:

    sed -ri.bak 's (src=").*/files/(.+[.]jpg") \1graphics/\2 g' *.xhtml
    

    通过在搜索表达式中提及一些上下文,它正在(合理地)努力确保它在正确的行上运行。

    sed用法说明:s命令后的第一个字符指示分隔符,这使我们/无需转义即可使用。

    • 0

相关问题

  • 从文本文件传递变量的奇怪问题

  • 虽然行读取保持转义空间?

  • MySQL Select with function IN () with bash array

  • `tee` 和 `bash` 进程替换顺序

  • 运行一个非常慢的脚本直到它成功

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve