Copying all files inside subdirectories and renaming instead of overwriting
Solution 1:
GNU cp(1)
has a backup option:
cp --backup SOURCE [SOURCE...] [DESTINATION]
This has the following effects which can be controlled with other options as described in the manual page of cp(1)
:
--backup[=CONTROL] make a backup of each existing destination file -b like --backup but does not accept an argument -S, --suffix=SUFFIX override the usual backup suffix
The backup suffix is
~
, unless set with--suffix
orSIMPLE_BACKUP_SUFFIX
. The version control method may be selected via the--backup
option or through theVERSION_CONTROL
environment variable. Here are the values:
none
,off
: never make backups (even if--backup
is given)numbered
,t
: make numbered backupsexisting
,nil
: numbered if numbered backups exist, simple otherwisesimple
,never
: always make simple backups
Example
cp --backup=existing --suffix=.orig ~/Music/* ~/Videos
This will copy all files in ~/Music
to ~/Videos
. If a file of the same name exists at the destination, it is renamed by appending .orig
to its name as a backup. If a file with the same name as the backup exists, the backup is instead renamed by appending .1
and, if that exists as well, .2
and so forth. Only then is the source file copied to the destination.
If you want to copy files in subdirectories recursively use -R
:
cp -R --backup=existing --suffix=.orig ~/Music ~/Videos
Solution 2:
Your problem is actually to find a cp
variant that creates the target file under a different name if it already exists. I'm not aware of a tool that does so, however, it's not hard to implement yourself:
cp -vn "$1" "$2"/ || cp -vn "$1" "$2"/"${1##*/}"~"$(md5sum "$1" | cut -f1 -d' ')"
This script calls cp
again in case it fails, appending the checksum to the filename. Flaw: If a third file with the same name shows up, it will overwrite the second file if they are identical.
Given that the above script is called saveCopy
and stored in the parent working directory, the following works:
$ find . -name 'z*.jpg' -exec ./saveCopy {} /tmp/Extracted/ \;
./a/z1.jpg -> /tmp/Extracted/z1.jpg
./a/z2.jpg -> /tmp/Extracted/z2.jpg
./a/z3.jpg -> /tmp/Extracted/z3.jpg
/tmp/Extracted/z3.jpg not overwritten
./b/z3.jpg -> /tmp/Extracted//z3.jpg~d41d8cd98f00b204e9800998ecf8427e
./b/z4.jpg -> /tmp/Extracted/z4.jpg
Be aware that the script only works for a single input file and if the target is a directory! It can certainly be improved ;-)