Inserting slugs with bash & sed
Sat, Sep 9, 2017Let’s use bash
and sed
to add a new line of dynamic content near the top of a bunch of files.
Motivation
I recently switched this site from using Jeykll to using Hugo. To do so without breaking my old site’s URLs, I found that I needed to insert a line of YAML front matter at the top of each post that looks something like this:
slug: "sed_insert"
Jekyll used the filenames as the URL slug, so for each post, I needed to insert the filename as the slug on a new line towards the top of the file:
---
title: "Inserting lines with sed"
date: 2017-09-09T13:52:28-07:00
slug: "sed_insert"
---
Getting the Slug
Because each filename matches the pattern *.markdown
, I can use one of the many bash string manipulation operators to lop off the “.markdown” suffix. The ${string%substring}
pattern will remove the shortest trailing match of substring from string:
❯ for f in *.markdown; do echo "${f%.markdown}"; done
connection-refused
debian-packages-in-docker
django-encryption-at-rest
docker-arm7-chip
nsenter_network_namespace
openvpn-with-docker
port-socket
stroke-width-transform
syn-backlog
unicode-python
Constructing the YAML
We can tinker with the loop a bit to add the necessary yaml sugar. The wonky quoting is says: echo the thing wrapped in double quotes, interrupting the double quotes on occasion to explicitly print a double-quote-symbol:
#!/bin/bash
for f in *.markdown
do
echo "slug: "'"'"${f%.markdown}"'"'
done
# prints
slug: "connection-refused"
slug: "debian-packages-in-docker"
slug: "django-encryption-at-rest"
slug: "docker-arm7-chip"
slug: "nsenter_network_namespace"
slug: "openvpn-with-docker"
slug: "port-socket"
slug: "stroke-width-transform"
slug: "syn-backlog"
slug: "unicode-python"
Inserting with sed
On my macbook, sed is really old. So I’ve installed GNU sed via brew install gnu-sed
, which installs it as gsed
. You should be able to do something similar on a linux machine with sed
.
The pattern 4 i
is interpreted by sed
as:
We want to tell sed
to do the following: on the fourth line (one-indexed), insert the following content. Fortunately for us, we can use the 4 ifoo
pattern to insert the word foo on line four! Let’s tie everything together to insert the correct yaml:
#!/bin/bash
for f in *.markdown
do
gsed -i -e "4 islug: "'"'"${f%.markdown}"'"' ${f}
done
Note that I’m using the -i
flag to do in-place modification of each file, rather than printing the modified contents to stdout, but dropping this flag will let you test things out without affecting file contents.