This blog is rendered by the means of a static site generator (SSG) called Hugo. Each blog post has a set of one or more tags associated to it. The more posts I create, the more consolidated the tags become.

Sometimes I need to rename tags after-the-fact to better reflect the underlying posts they represent.

This is how I typically do it. Start from the root of the git repository, then do:

% for file in content/posts/**/*.md; do gsed -i -e 's/- german/- deutsch/g' "$file"; done

The example above renames german -> deutsch.

This isn’t the most robust way to do so, but it’s the quickest one. For extra robustness, I’d do:

% fd -t f -e md -e gsed -i -x 's/- german/- deutsch/g'

…however it’s always easier to remember the for loop syntax than the fd one.

Why fd instead of a for loop?

fd(1) is more elegant than shell wildcards. Although, in practice, both ways are equivalent and should yield no difference.

Why gsed instead of sed?

I am on macOS. The GNU version of sed does not create backup files, which is what I want in most cases. There’s no need for backups because everything is checked into git already; if I make a mistake, I can always git reset --hard or git checkout. The BSD version of sed will leave this mess behind:

% fd -t f -e md -x /usr/bin/sed -i -e 's/- german/- deutsch/g'
% git st
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   2022-02-27-linux-us-international-keyboard-layout.md
	modified:   2022-04-03-translating-german-to-english.md
	modified:   2024-01-29-anki-find-all-notes-with-an-empty-field.md

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	2014-01-07-testando-uma-iso-no-linux-sem-o-virtualbox.md-e
	2014-04-18-mini-recovery-tipico-via-usb.md-e
	2014-05-01-instalando-o-gentoo-a-partir-do-arch.md-e
	2014-09-28-my-first-ebuild.md-e
	2015-01-07-the-eudyptula-challenge.md-e
[...]

There are even more of these *-e files, and they are super annoying. It’s easy to get rid of them:

% rm **/*-e

…but why bother, if we can just stick to the more familiar GNU sed anyway?

Caveats

Finally, note the caveat: this find and replace is naive and could end up replacing false positives! Nonetheless, I’m still a big fan of this approach, because it’s the quickest one. As my blog is checked into git anyway, I can always easily review the changes before committing them:

% git diff

If there are too many diffs, then prefer an incremental approach:

% git add -p

Happy tag renaming! Well, this only happens every once in a while anyway.