一行代碼提取markdown文件中圖片

一個博客的誕生中 說到還有幾件沒完成的事情,其中一件就是要將markdown中的圖片進行備份,這篇文章將介紹如何使用shell對md文件中圖片連接進行解析並下載
本文記錄了整個思考和實現的過程,有些囉嗦,不想看詳細內容的能夠直接用下面的命令行,若是是mac,須要安裝gnu-sed並使用gsed代替自帶的sedgit

grep -oP "\!\[.*?]\(.*?\)" 計算機基礎-內存管理介紹.md | sed  -E  "s/(\!\[.*]\()(https?:\/\/.+\.(png|jpe?g|webp|gif|svg))(.*\))/\2/gi" |xargs  wget –c -N
複製代碼

image.png

  • grep使用懶惰模式匹配圖片連接
  • sed將markdown圖片連接替換成其中的URL
  • wget下載

寫了一個bash腳本,能夠遍歷文件夾中的md文件,對其中圖片批量下載
md_img_dl
歡迎stargithub

匹配圖片連接的正則式

markdown中圖片連接的格式仍是比較清晰的![描述](圖片url),寫出來的正則式爲web

\!\[.*\]\(.+\)
複製代碼

使用grep輸出圖片連接

隨便找了一個md文件測試了下正則表達式

grep  "\!\[.*\]\(.+\)" 計算機基礎-內存管理介紹.md
複製代碼

發現並無出現預期的結果,查了下貌似grep的basic regular expression 不支持 + 這個元字符。因此須要使用extended regular expression ,用法爲 egrep 或者 grep -E ,最後可用的命令爲shell

grep -E  "\!\[.*\]\(.+\)" 計算機基礎-內存管理介紹.md
複製代碼

結果爲
express

image.png

只匹配圖片連接部分

上面匹配的連接部分是完整的,可是事實上咱們須要的是url的部分,那麼是否能夠將url單獨提出來呢?
這種看上去就須要用到正則表達式中的先後查找功能,開始修改正則式bash

(?<=\!\[.*\]\()(.+)(?=\))
複製代碼

解釋下這個正則幹了什麼
(?<=\!\[.*\]\() 中 ?<= 表示這個子表達式是個向後查找表達式。表示對該表達式進行匹配可是不含在最後的結果,向後查找表達式匹配的內容位於整個匹配的前面,這個表達式 ![.*]( 匹配 ![xxx](
(?=\)) 這個是向前查找表達式,和向後查找相似,不過匹配的是字符串最後的位置,這裏匹配圖片連接最後的 )
這樣就能夠匹配到整個圖片連接而最終結果中只包含圖片url了
vscode中的搜索結果
markdown

image.png

使用grep進行匹配

grep -E "(?<=\!\[.*\]\()(.+)(?=\))" 計算機基礎-內存管理介紹.md
複製代碼

結果打印出來是app

grep: repetition-operator operand invalid
複製代碼

並不能成功的匹配urlsvg

緣由多是vscode太強大了,大部分正則表達式的實現是不支持可變長度的向後查找的,只能換其餘方法了

使用sed進行匹配

sed是一個進行字符串替換的工具,由於上面的方式是由於向後查找的問題,因此咱們不使用向後查找,而使用匹配整個圖片連接的表達式,再用sed提取出其中表明url的子表達式替換整個的圖片連接,以此完成只匹配圖片url的目的

sed  -E  "s/(\!\[.*]\()(.+)(.*\))/\2/g" 計算機基礎-內存管理介紹.md
複製代碼

s///g s表示替換模式,g表示匹配每一行有行首到行尾的全部字符,加g則一行有多個圖片連接能夠匹配處理,不加只能匹配第一個
\2 表明第二個子表達式,即用url部分替換整個 ![描述](url)

image.png

執行以後能夠看到圖片連接已經變成url了,可是其餘沒匹配到的內容仍是輸出出來了

只輸出匹配內容

這裏有兩個思路,
思路是先使用grep先過濾一遍再使用sed替換,須要使用-o選項,只打印正則匹配的部分

grep -o "\!\[.*]\(.*\)" 計算機基礎-內存管理介紹.md | sed  -E  "s/(\!\[.*]\()(.+)(.*\))/\2/g"
複製代碼

image.png

或者直接在sed中 -np子命令一塊兒使用,只打印匹配的內容

sed  -E -n  "s/(\!\[.*]\()(.+)(.*\))/\2/gp" 計算機基礎-內存管理介紹.md
複製代碼

以前對這個sed命令有個誤解。

  • -n 和p命令一塊兒使用只能屏蔽不匹配的行,若是一行裏有不匹配的內容仍是會顯示出來

因此單純使用sed去過濾匹配內容看上去有點麻煩

懶惰匹配

最近在寫腳本的時候發現markdown中圖片連接是能夠作爲超連接的一部分,相似下面這種

[![圖片描述](圖片url)](頁面url)
複製代碼

這種狀況用上面的正則表達式由於使用了貪婪型元字符,匹配的內容是儘量多的,它把下面的當作一個總體去匹配

![圖片描述](圖片url)](頁面url)
複製代碼

這種狀況向咱們須要使用懶惰型元字符,將 * + 替換爲 *? +?

sed是不支持懶惰匹配的,而咱們先用grep過濾了一遍,grep能夠支持懶惰匹配,須要加上-P選項
修改完命令爲

grep -oP "\!\[.*?]\(.*?\)" 計算機基礎-內存管理介紹.md | sed  -E  "s/(\!\[.*]\()(.+)(.*\))/\2/g"
複製代碼

下載圖片

命令行中下載經常使用wget
將前面的輸出經過管道重定向給wget做爲參數,這裏須要使用xargs

grep -oP "\!\[.*?]\(.*?\)" 計算機基礎-內存管理介紹.md | sed  -E  "s/(\!\[.*]\()(.+)(.*\))/\2/g" |xargs  wget –c -N
複製代碼

爲了讓wget在本地有圖片的時候就不去下載,先加了 -N 選項,發現有些圖片能夠,有些圖片仍是會下載第二次,應該依賴於服務端的實現
再加上 -c 斷點續傳的選項,我這邊使用的圖牀都知足了本地有圖片就不下載的需求
第一次正常下載圖片

image.png

第二次提示 304 Not Modified不用從新下載

image.png

小修小補

加上http/https的校驗。以及圖片格式校驗,主要在sed這一步,加上i不區分大小寫

sed  -E  "s/(\!\[.*]\()(https?:\/\/.+\.(png|jpe?g|webp|gif|svg))(.*\))/\2/gi"
複製代碼

相關文章

一個博客的誕生
聊一聊shell中的條件控制

相關文章
相關標籤/搜索