Better Dotfiles

September 2024

Whilst reorganising my dotfiles I avoided superfluous dotfile managers and the limitations of the "version control $HOME" method by instead including first-line comments of the form <comment delimiter> ln <link name> in files which needed to be symlinked.

Examples:

~: head -n 1 ~/dotfiles/helix/config.toml
# ln ~/.config/helix/config.toml

~: head -n 1 ~/dotfiles/polybar/config.ini
; ln ~/.config/polybar/config.ini

~: head -n 1 ~/dotfiles/x/keyboard.conf
# ln /etc/X11/xorg.conf.d/00-keyboard.conf

The files can be scanned and symlinks can be created with some awk magic:

find ~/dotfiles -type f \
  | xargs -I {} awk 'NR == 1 && $2 == "ln" {
    system("ln -sf " FILENAME $3)
  }' {}

If we change our awk to just print, add a substitution for ~, ignore the .git directory when searching for files and package everything up in a function we end up with:

list_symlinks () {
  find $(dirname $0) \
    -type f ! -path '*.git/*' \
    | xargs -I {} awk 'NR == 1 && $2 == "ln" { print FILENAME " " $3 }' {} \
    | sed "s|^./|$(pwd)/|;s|~|$HOME|"
}

list_symlinks can then be piped into awk to create utility commands for managing symlinks:

# create symlinks
list_symlinks | awk '{system("ln -sf " $1 " " $2)}'

# remove all symlinks
list_symlinks | awk '{system("rm " $2)}'

# list symlinks
list_symlinks | awk '{ print $2 " -> " $1 }' | column -t

Using readlink we can enhance our symlink list to show broken symlinks:

echo -e "$( \
  [[ $(readlink $2) = $1 ]] \
    && echo "\033[32m✓" \
    || echo "\033[31m✗" \
  ) $2 -> $1 \033[0m"

Example output:

✓ ~/.i3/config -> ~/dotfiles/i3/config
✓ ~/.zshrc -> ~/dotfiles/zsh/.zshrc
✗ ~/.xinitrc -> ~/dotfiles/x/.xinitrc
✗ ~/.gitconfig -> ~/dotfiles/git/.gitconfig

We can also use the power of awk to remove old links when we update our files (this sits nicely in a git post-commit hook).

git diff HEAD~ | awk '/\-\S*\s+ln/ {
  if(prevLine ~ /@@ -1/) {
    system("rm " $3)
  }
} { prevLine=$0 }'

See my dotfiles for a full script which includes escalating with sudo when required.

What I like about this method is that:

Try it and see what you think.

» Comments on HN
< Home