在一個博客的誕生中 說到還有幾件沒完成的事情,其中一件就是要將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
複製代碼
寫了一個bash腳本,能夠遍歷文件夾中的md文件,對其中圖片批量下載
md_img_dl
歡迎stargithub
markdown中圖片連接的格式仍是比較清晰的![描述](圖片url)
,寫出來的正則式爲web
\!\[.*\]\(.+\)
複製代碼
隨便找了一個md文件測試了下正則表達式
grep "\!\[.*\]\(.+\)" 計算機基礎-內存管理介紹.md
複製代碼
發現並無出現預期的結果,查了下貌似grep的basic regular expression
不支持 +
這個元字符。因此須要使用extended regular expression
,用法爲 egrep
或者 grep -E
,最後可用的命令爲shell
grep -E "\!\[.*\]\(.+\)" 計算機基礎-內存管理介紹.md
複製代碼
結果爲
express
上面匹配的連接部分是完整的,可是事實上咱們須要的是url的部分,那麼是否能夠將url單獨提出來呢?
這種看上去就須要用到正則表達式中的先後查找功能,開始修改正則式bash
(?<=\!\[.*\]\()(.+)(?=\))
複製代碼
解釋下這個正則幹了什麼
(?<=\!\[.*\]\()
中 ?<= 表示這個子表達式是個向後查找表達式。表示對該表達式進行匹配可是不含在最後的結果,向後查找表達式匹配的內容位於整個匹配的前面,這個表達式 ![.*]( 匹配 ![xxx](
(?=\))
這個是向前查找表達式,和向後查找相似,不過匹配的是字符串最後的位置,這裏匹配圖片連接最後的 )
這樣就能夠匹配到整個圖片連接而最終結果中只包含圖片url了
vscode中的搜索結果
markdown
grep -E "(?<=\!\[.*\]\()(.+)(?=\))" 計算機基礎-內存管理介紹.md
複製代碼
結果打印出來是app
grep: repetition-operator operand invalid
複製代碼
並不能成功的匹配urlsvg
緣由多是vscode太強大了,大部分正則表達式的實現是不支持可變長度的向後查找的,只能換其餘方法了
sed是一個進行字符串替換的工具,由於上面的方式是由於向後查找的問題,因此咱們不使用向後查找,而使用匹配整個圖片連接的表達式,再用sed提取出其中表明url的子表達式替換整個的圖片連接,以此完成只匹配圖片url的目的
sed -E "s/(\!\[.*]\()(.+)(.*\))/\2/g" 計算機基礎-內存管理介紹.md
複製代碼
s///g
s表示替換模式,g表示匹配每一行有行首到行尾的全部字符,加g則一行有多個圖片連接能夠匹配處理,不加只能匹配第一個
\2
表明第二個子表達式,即用url部分替換整個 ![描述](url)
這裏有兩個思路,
思路是先使用grep先過濾一遍再使用sed替換,須要使用-o選項,只打印正則匹配的部分
grep -o "\!\[.*]\(.*\)" 計算機基礎-內存管理介紹.md | sed -E "s/(\!\[.*]\()(.+)(.*\))/\2/g"
複製代碼
-n
和 p
子命令一塊兒使用,只打印匹配的內容sed -E -n "s/(\!\[.*]\()(.+)(.*\))/\2/gp" 計算機基礎-內存管理介紹.md
複製代碼
以前對這個sed命令有個誤解。
因此單純使用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
斷點續傳的選項,我這邊使用的圖牀都知足了本地有圖片就不下載的需求
第一次正常下載圖片
第二次提示 304 Not Modified不用從新下載
加上http/https的校驗。以及圖片格式校驗,主要在sed這一步,加上i不區分大小寫
sed -E "s/(\!\[.*]\()(https?:\/\/.+\.(png|jpe?g|webp|gif|svg))(.*\))/\2/gi"
複製代碼