Copying all files inside subdirectories and renaming instead of overwriting

5

4

I have a number of images inside subdirectories of another directory which I'd like to copy to one single directory so all the images are in one place.

After a bit of searching, I found and then modified some things to create this command:

find . -name "z*.jpg" -exec cp '{}' ~/Extracted/ \;

This seemingly worked, however I found that images with the same name would be overwritten, so then I did this:

find . -name "z*.jpg" -exec cp -n '{}' ~/Extracted/ \;

But now images with the same name are simply ignored.

Is there anyway I could do this so every image is copied over and images with the same name are renamed?

user183714

Posted 2013-02-19T16:21:18.093

Reputation:

Answers

7

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 or SIMPLE_BACKUP_SUFFIX. The version control method may be selected via the --backup option or through the VERSION_CONTROL environment variable. Here are the values:

  • none, off: never make backups (even if --backup is given)
  • numbered, t: make numbered backups
  • existing, nil: numbered if numbered backups exist, simple otherwise
  • simple, 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

David Foerster

Posted 2013-02-19T16:21:18.093

Reputation: 829

While the other answer solved my problem, this solution is much easier to implement. This may be useful in the future.

Thanks! – None – 2014-10-26T22:45:33.223

3

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 ;-)

barbaz

Posted 2013-02-19T16:21:18.093

Reputation: 2 696

You can make it more consistent just omitting copying the original filename, using only the code after ||: cp -vn "$1" "$2"/"${1##*/}"~"$(md5sum "$1" | cut -f1 -d' ')" - the problem however is that the file extension gets messed up with the md5sum – Robin Manoli – 2017-01-23T15:02:27.397

Nice, +1. Why would it be a flaw to overwrite identical files? – terdon – 2013-02-19T22:15:44.023

@terdon the flaw is actually more that you still end up with 2 copies of an identical file, because the first copy doesn't have the hash attached. It's not consistent. However, I just wanted to keep the example small, if one wants to use something like this on a regular basis one should think of a slightly more sophisticated solution. – barbaz – 2013-02-20T08:52:10.380