Better cp Command, Before Changing Config Files Manually

People might manually change critical config files in servers occasionally. For example, /etc/hosts, /etc/hostname, etc.

As an experienced operator, you will remember to backup, before making any changes. Right? What would you do? cp /etc/hosts /etc/hosts.bak.

But is that good enough?

Backup Config Files Before Manual Changes

Original Article:

Rule #1: Manual Changes Are Troublesome.

Try our best to avoid them. Use configuration management tools if possible. Chef, Puppet, Ansible, whatever. (Related Reading: Automatically Track All Change History)

Back to the earth. You might still want to change files directly in some cases. Yes, I totally understand. Quick fix in non-critical envs. Test some stuff in local dev envs.

Version 1: Normal way

People usually backup like below.

# Simple backup
cp /etc/hosts /etc/hosts.bak

# Or a shorter command
cp /etc/hosts{,.bak}

What are the potential problems?

Issue: Backup will be overwrite, if we re-run the cp command.

Most of the time, we will change files more than once. Yes, whenever we run cp command, we will get a new backup. However we will lose the previous backup(s).

So we only have the backup of intermediate versions. No way to go back to the state of the very beginning!

Version 2: Avoid overwrite previous backup

To avoid overwrite, we can add timestamp to the cp command:

cp /etc/hosts \
  /etc/hosts_$(date +'%Y-%m-%d_%H%M%S')

What now? Issue: garbage files of old backup in the servers.

Whenever we make a change, we literally generate a new “garbage” file. This will occupy disk capacity. Furthermore it might confuse our colleagues or even ourselves. We need to be careful to clear up those files.

Version 3: Reclaim disk from old backup

Move backup files to a centralized directory. Then we can easily remove old backup or enforce data retention.

cp /etc/hosts \
 /data/backup/hosts_$(date +'%Y-%m-%d_%H%M%S')

Looks perfect? Not yet.

Issue: Hard to tell the original location of the backup. We’ve lost the directory hierarchy.

Version 4: Keep directory hierarchy of original files

Okay, our copy command looks better.

cp /etc/hosts \
 /data/backup/etc/hosts_$(date +'%Y-%m-%d_%H%M%S')

One more improvement.

When we backup different files, we need to type too many stuff. Isn’t it?

Version 5: Use bash alias for fast input

We can define a bash alias. Then use it like below.

# sample: backup file
mybackup /etc/hosts

# sample: backup directory
mybackup /etc/apache2

Here is how.

  • Step 1: Create /etc/profile.d/ with below content
#!/bin/bash -e
mybackup() {
    src_file=${1?"What files to backup"}

    # get default value from environment variable
    if [ -n "$BAK_ROOT_DIR" ]; then

    parent_dir=$(dirname "$src_file")
    short_fname=$(basename "$src_file")
    date="$(date +'%Y%m%d.%H%M%S')"
    if [ -f "$src_file" ]; then
        mkdir -p "$bak_dir"
        echo "cp $src_file ${bak_dir}/${short_fname}-${date}"
        cp "$src_file" "${bak_dir}/${short_fname}-${date}"
    elif [ -d "$src_file" ]; then
        mkdir -p "$bak_dir-${short_fname}-${date}"
        echo "cp -r $src_file $bak_dir-${short_fname}-${date}"
        cp -r "$src_file" "$bak_dir-${short_fname}-${date}"
        echo "Error: $src_file doesn't exist"
        exit 1
  • Step 2: Install bash alias
# install bash
chmod 755 /etc/profile.d/
source /etc/profile

# create destination directory
mkdir -p /data/backup

  • Step 3: Try it. And have fun!
source /etc/profile

# sample: backup file
mybackup /etc/hosts

# sample: backup directory
mybackup /etc/apache2

# check backup files. 
# Install tree package, if missing
tree /data/backup

Beyond cp command

To avoid mess up config files, here are some alternatives of cp:

  1. Replace manual changes with configuration management tools.
  2. Upload backup to remote server. If your files are not mission critical, you can try With one curl command, you get a safe http download link.
  3. Use source control. For example, create a local git repo, create hard link of critical files/directories, then git commit. etckeeper is an nice wrapper of this mechanism.[1]
  4. Use inotify to subscribe filesystem events of change/create/delete/etc.[2]