Script to update image embed links in Markdown files

Technology keeps moving but this post has not.

What you're about to read hasn't been updated in more than a year. The information may be out of date. Let me know if you see anything that needs fixing.

I'm preparing to migrate this blog thingy from Hashnode (which has been great!) to a GitHub Pages site with Jekyll so that I can write posts locally and then just do a git push to publish them - and get some more practice using git in the process. Of course, I've written some admittedly-great content here and I don't want to abandon that.

Hashnode helpfully automatically backs up my posts in Markdown format to a private GitHub repo so it was easy to clone those into a local working directory, but all the embedded images were still hosted on Hashnode:

2![Clever image title](

I wanted to download those images to ./assets/images/posts-2020/ within my local Jekyll working directory, and then update the *.md files to reflect the correct local path... without doing it all manually. It took a bit of trial and error to get the regex working just right (and the result is neither pretty nor elegant), but here's what I came up with:

 2# Hasty script to process a blog post markdown file, capture the URL for embedded images,
 3# download the image locally, and modify the markdown file with the relative image path.
 5# Run it from the top level of a Jekyll blog directory for best results, and pass the 
 6# filename of the blog post you'd like to process.
 8# Ex: ./
12imageUrls=($(grep -o -P '(?<=!\[)(?:[^\]]+)\]\(([^\)]+)' $postfile | grep -o -P 'http.*'))
13imageNames=($(for name in ${imageUrls[@]}; do echo $name | grep -o -P '[^\/]+\.[[:alnum:]]+$'; done))
14imagePaths=($(for name in ${imageNames[@]}; do echo "assets/images/posts-2020/${name}"; done))
15echo -e "\nProcessing $postfile...\n"
16for index in ${!imageUrls[@]}; do
17    echo -e "${imageUrls[index]}\n => ${imagePaths[index]}"
18    curl ${imageUrls[index]} --output ${imagePaths[index]}
19    sed -i "s|${imageUrls[index]}|${imagePaths[index]}|" $postfile

I could then run that against all of the Markdown posts under ./_posts/ with:

1for post in $(ls _posts/); do ~/scripts/ $post; done

And the image embeds in the local copy of my posts now all look like this:

2![Clever image title](lhTnVwCO3.png)