Copy files with renaming

Many GNU tools such as cp, mv and tar support creating backup files when the target exists. That is, when copying foo to bar, if there is already a file called bar, the existing bar will be renamed, and after the copy bar will contain the contents of foo. By default, bar is renamed to bar~, but the behavior can be modified:

                                # If a file foo exists in the target, then…
cp -r --backup source target    #   rename foo → foo~
cp -r --backup=t source target  #   rename foo → foo.~1~ (or foo.~2~, etc)

There are other variants, such as creating numbered backups only when one already exists. See the coreutils manual for more details.


I tried

apropos copy | grep "(1)" 

to find possible candidates, and mcopy showed up.

man mcopy 

shows a promising option -D clash-option isn't that cool? But not so cool - it isn't described. But there are some hints to mtools.dvi, which I searched on my system, without success, and via google, without success, but then, with google, I searched directly for mcopy clash-option and found this site.

I made a short test

mcopy -D A f* a 

to tests for autorename and targetdir a - instead of autorenaming it asked me for every file to ignore or override, that stupid s... .

My version is mtools-4.0.10 and the help page is from 1996 - 15 years old. Should we really lost some features, meanwhile?

I would split the work into two steps:

  • Make a short function, which generates a unique name for a file, if that name is occupied.
  • Run find, and execute that script for every file you wish to copy.

Shall we assist in this approach? :)

Here is a script, to autorename files:

#!/bin/bash

name=$1
target=$2

autorename () {
name=$1
target=$2
no=$3 

test -e ${target}/${name}.$no && autorename ${name} ${target} $((no+1)) || cp ${name} ${target}/${name}.$no 

}

test -e ${target}/${name} && autorename ${name} ${target} 0 || cp ${name} ${target} 

and this is my test invocation:

find -maxdepth 1 -name "fo*" -type f -exec ./autorename.sh {} /mnt/hidden/test/a ";"

Note: -maxdepth, -name and -type where used to restrict the number of affected files dramatically. I didn't test the script for deeper file structures, nor for blanks in filenames and other, funky characters like linefeed, pagefeed and so on.

I used .1 because it doesn't make trouble in most commands, while a ( and a ) often need masking.