0

I have folders with almost same files and names in multiple locations and drives. I would like to move them all to a single location. The structure is something like below:

Folder 1
--> Folder 1.1
-----> File1.txt
-----> File2.txt
Folder 2
--> Folder 2.1
-----> File1.txt
-----> File2.txt
...
-----> FileN.txt

I would like to move them all to another single location on another drive. When copying or moving, I would like to rename the file being moved to something like FileN-copy-1.txt, etc. This is similar to the behaviour when you move files in finder on mac and it names the files incrementally if you select "Keep both".

I have tried using rsync but it does not seem to have an option where i can rename the new file being moved.

Any help would be greatly appreciated.

3
  • Are they all .txt files? Do I understand correctly: you want all files in a single target directory with no subdirs?
    – FelixJN
    Commented Feb 8, 2021 at 11:17
  • No they can be any type. Mostly images. There folders with any level of sub dirs. Commented Feb 9, 2021 at 4:07
  • I actually built upon the script posted by @Denis. I will share it when I have polished it a bit. Thanks. Commented Feb 10, 2021 at 6:16

3 Answers 3

1

You can make simple bash script like this

#!/bin/bash

MyFolder=/my/folder
DestFold=/destinatin/folder
CpNum=10
i=0

for FlN in $MyFolder; do
  FlNo = echo $FlN |awk -F\/ '{print $NF}'
  if [! -f $DestFold/$FlNo ]; then
    cp $FlN $DestFold/
  else
    FlNo = echo $FlN |awk -F\/ '{print $NF}' 
    while [ $i -lt $CpNum ]; do
      i=$[$i+1]
      if [ ! -f $DestFold/${FlNo%.txt}-copy-$i.txt ]; then
        cp $FlN $DestFold/${FlNo%.txt}-copy-$i.txt
        i=$CpNum
      fi
    done
  fi
done

so you enter searching and destination folder, and then run the script (before make it executable by

chmod 755 yourscript

This script will look for files, and put them in variable (FlN) and cut variable to just file name without folders in front (FlNo), than copy if no file like this present. If present he will create a file with added -copy-X just before the ending of the file name (X is the number of copy). A variable $CpNum will be number of maximum copies of each file (can be safely increased) Currently works for .txt files, but you can modify it. You can further play to add option to call a script with argument, or make it to many different extensions

3
  • It would need to be recursive. Commented Feb 10, 2021 at 6:17
  • it is recursive if you use loop in this manner @SheikhAzad
    – DenisZ
    Commented Feb 10, 2021 at 8:55
  • It is not recursive. Moreover you are limiting copies to a max of 10. I have another way of doing it and will post it here soon. Commented Feb 17, 2021 at 23:41
1

rsync is a good first choice if you want to copy all files and subdirectories under a directory. It does have an option for not overwriting files, the -b backup option.

However, by default the backup is using a naming scheme that's not useful for this purpose (an added ~ character at the end of the filename, which some tools are hiding as unneeded backup files).

There is an option to change it (--suffix newending), which can be anything, but it's still tacked on at the end, and not removing any previous extension. If that works for you, this is an easy job for rsync. Note that it's a proper backup - files with the same names that are otherwise identical will not have two copies.

For example, in your case two commands would be needed to populate the destination from two sources:

rsync -av "Folder 1/" "New Folder/"
rsync -av -b --suffix -copy.txt "Folder 2/" "New Folder/"

Note the peculiar quoting required for the files with white spaces, and the ending / denoting the contents of the directory (starting under the directory, not including it).

Files that are already present from Folder 1 will be tacked on a -copy.txt such as:

; ls -R1 New\ Folder
'New Folder':
f1.txt
f1.txt-copy.txt
f2.txt
f2.txt-copy.txt

Update:

Both commands essentially synchronise from the first directory to the second, and the additional command would indeed overwrite anything present in the destination, the backup option changes this so that the file that would otherwise be destroyed is kept as a backup. So indeed, the files from the second line would retain their names. This still might be useful for the original purpose if the commands were run in a different order.

That is, if you use rsync with the backup and suffix option - then the destination will have the azad.txt file replaced, but the backup option would keep the previous file in the destination renamed with the new suffix.

2
  • I am apprehensive about using commands before being very sure about what they do. So if there is a file named azad.txt and it is rsynced where another file with the same name exists. Would that file be renamed or the one that is getting transferred? Commented Feb 9, 2021 at 4:02
  • @chexum OP wanted the existing files to keep their names and new files to be renamed.
    – FelixJN
    Commented Feb 9, 2021 at 8:43
1

I'll try to meet in the middle regarding complexity with the two answers here. The following is a one liner that would accomplish what you require:

srcdir=<Source Directory>;dstdir=<Destination Directory>;cd $srcdir;for srcfile in *;do if [ -f $dstdir$srcfile ] then $srcfile $dstdir${srcfile%.*}-copy.${srcfile##*.}; else cp $srcfile $dstdir$srcfile; fi; done

Broken out to be more readable it would look like this:

srcdir=<Source Directory>
dstdir=<Destination Directory>

cd $srcdir

for srcfile in *
do
    if [ -f $dstdir$srcfile ]
        then 
            cp $srcfile $dstdir${srcfile%.*}-copy.${srcfile##*.}
        else
            cp $srcfile $dstdir$srcfile
    fi
done

To explain how this works, this has you input a source and destination directory. It will cd into that directory so that the format of $srcfile is not a full path and doesn't require string expansion every time you use the variable. As it is right now it will look at every file from $srcdir, check if that file exists in $dstdir, and if it does it will insert a -copy, and then cp the file to $dstdir$srcfile. between the filename and the extension(${srcfile%.} prints just the file name and ${srcfile##.} prints just the extension). if it does not exist it will just copy as normal.

To explain why I am not handling multiple copy cases here is because the scenario doesn't specify more than a single directory to another single directory on a one time only copy, so its not possible for this case to exist. That being said use with caution, this will overwrite or append (depending on src vs dst directory) files with a -copy. naming convention.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .