Tuesday, November 11, 2014

Backup Configuration Files

Anyone who manages a Unix-like system has edited a configuration file from time to time.  At an absolute minimum, you should copy these files before editing them.  Otherwise, you could get through a few lines of editing, break something (or just want to go back to your old setup), and not know how to go back.

Here is a quick trick I came up with for handling this.  There are better ways, but this can be dropped right into any Unix-like system with very little effort. That easily includes MacOS, Linux, and FreeBSD.

First, I started with this trick from http://osxdaily.com/2012/06/11/make-a-quick-backup-of-a-file-from-the-command-line/.

cp file.txt{,.backup}

This will copy file.txt to file.txt.backup .

Unfortunately, the next time its done, file.txt.backup will be overwritten and the history of our changes over time will be lost.

So I decided to end the backup files with the date. Done correctly, this will alphabetize them into chronological order and allow some rudimentary change-tracking in the future using the diff command. So let's look at this:

date "+%Y%m%d%H%M%S"

It outputs the current date and time in YYYYMMDDHHMMSS format. In other words, it prints out the year, then month, then day of month, then the time. So 9:59am on July 11, 2014 will come out as 201407110959.

Note that this is done with "padding zeros" to make sure that it alphabetizes into chronological order. You can see it in the "07" for July, which will now come before December. This is because 07 is alphabetically before 12, even though July and Jul are alphabetically after December and Dec.

So using that and the cp command from earlier, we now have this.
cp file.txt{,.`date "+%Y%m%d%H%M%S"`}

This copies file.txt to file.txt.<timestamp>. Using the example date above (9:59am on July 11, 2014), that would be file.txt.201407110959. This is the effect we want.

In a bash shell script, "$1" references the first string after the command, as parsed by whitespace delimiting.

So using that, we get this shell script:

#!/bin/bash
cp $1{,.`date "+%Y%m%d%H%M%S"`}
Let's put that in a file called script.sh and then make sure its executable with chmod 755 script.sh. This allows "./script.sh file.txt" to copy file.txt to file.txt.<timestamp> without having to manually calculate the timestamp.

Name this "backup" and copy it to your ~/bin, /usr/local/custom, or some other location in your $PATH. Then set it to chmod 0755, if you haven't done so yet.
The next time you have to edit a configuration file, just type "backup config-file.txt" before you edit it.

So, to re-cap:
  1. Make a file called "backup" and put the above two line script in it.
  2. Put "backup" someplace where it will be in your $PATH, such as ~/bin or /usr/local/bin or /usr/local/custom.
  3. Make sure that location is actually in your $PATH.
  4. Use chmod 755 /path/to/backup to make sure its executable.
  5. From now on, before editing configuration files you should type "backup <config file>" to make a quick copy that you can revert to.
Note: There are better ways to track your server's configuration changes, but they're not always an option. Sometimes policy gets in the way. Sometimes convincing the other system administrators to use the tools is hard. This solution should work on any system and provides a predictable and reliable tool with a minimum of training and without installing any additional software. I recommend starting with this and, where available, eventually moving to tools like RCS or git.