Originally published August 17, 2021 @ 12:09 pm

Having to undo stupid changes to config files is an unfortunate side effect of too few sysadmins supporting too many servers. The VIM editor has some built-in file backup options. However, I find these options very limited and generally not particularly well suited to sysadmin work.

A solution has been around for decades (for vi and other CLI editors), and it’s a wrapper script. Here’s my version, and I tried to keep it simple. You can download the script from my GitHub repo or copy it below. Make it executable and add a link – say, /usr/bin/vish.

#!/bin/bash
declare -a a an
i=0
for f in "${@}"
do
  if [ -f "${f}" ]
  then
    fn="$(dirname "${f}")/$(basename -- "${f%.*}")_$(date -d @$(stat -c %Y "${f}") +'%Y-%m-%d_%H%M%S')@$(date +'%Y-%m-%d_%H%M%S')$([[ "${f}" = *.* ]] && echo ".${f##*.}" || echo '')"
    a+=("${f}")
    an+=("${fn}")
    /bin/cp -p "${a[$i]}" "${an[$i]}"
    (( i = i + 1 ))
  fi
done
vim "${@}"
if [ $? -eq 0 ]; then
  for ((i = 0; i < ${#a[@]}; i++))
  do
    if cmp -s "${a[$i]}" "${an[$i]}"
    then
      /bin/rm -f "${an[$i]}" 2>/dev/null
    fi
  done
fi

It will help if you run it the same way you would run the vim command by providing one or more filenames you wish to edit. The path to the files can be either absolute or relative. For example:

vish /etc/hosts /etc/resolv.conf

# or

cd /etc && vish hosts resolv.conf

The backup files are created when you run the wrapper script. When you exit VIM, the script will compare current versions of the files you edited to the backups it created earlier. If there was no change, the unneeded backups will be removed. Now, if you check the /etc folder, you will see the two new backup files:

ls -als /etc | egrep "hosts|resolv"

 4 -rw-r--r-- 1 root root       1775 Aug 17 10:08 hosts
 4 -rw-r--r-- 1 root root       1775 Aug 17 10:08 hosts_2021-08-17_100812@2021-08-17_113833
 0 -rw-r--r-- 1 root root        192 Aug 16 18:44 resolv_2020-10-28_005723@2021-08-17_113833.conf
 0 drwxr-xr-x 1 root root       4096 Oct 28  2020 resolvconf
 0 lrwxrwxrwx 1 root root         29 Oct 28  2020 resolv.conf -> ../run/resolvconf/resolv.conf

The backup filename format goes something like this:

<original_filename_without_extension>_<original_timestamp>@<current_timestamp>.<original_extension>

This tells me when the file was last modified and its previous modification date – both can be critical pieces of information when trying to figure out why something stopped working.