Bash

sed 替換圖像的路徑

  • October 6, 2021

我需要替換目錄中多個 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適合這個嗎?

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 {} +

如果它是 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屬性值的那些也是可能的。但是您的問題中沒有足夠的細節來有效地解決這些可能性。

引用自:https://unix.stackexchange.com/questions/670634