How to move files via batch file but if file already exist move elsewhere? - windows

I am trying to move files to a particular folder
(destination folder), but I do not want to overwrite any
files. Instead, if the file already exist in that particular
folder (destination folder), then move that file in another
folder (overflow folder), but keep folder structure.
I tried with xcopy and robocopy, but It appears that it
can't be done like that.
This is the script I use to move files but not overwrite.
robocopy "C:\DummySourcePath\" "C:\DummyDestantionPath\" /E /XC /XN /XO

Now it looks like your goal is to take a folder or directory and take all contents from this folder (including from sub-directory's) and copy it to one main folder. Any duplicate files you want rather to be sent to an overflow rather then to be overwritten.
If you don't want to overwright any files, an overflow folder will work. However what if there are two duplicate files trying to be dumped into the overflow directory? To get around this, we can simply name {File} to {File}(1), {File}(2), exc. This part of the script was taken from michael_heath on the post - batch script to copy files listed in a txt document and keep duplicates.
Essentially we are using an FOR /R statement along with an IF statement to check if the target directory contains the file or not. If it does, the ELSE will move it to overflow with further anti-overwright protections.
#ECHO OFF
#setlocal enableextensions enabledelayedexpansion
rem | Configure directories
set "source=C:\Source-Directory"
set "target=C:\Target-Directory"
set "overflow=Overflow-Directory"
rem | Scan target directory for a duplicate file name.
rem | If a duplicate was found, run a function to copy it to a overflow directory.
rem | If it already exists in the overflow directory rename it to {Name}(1), {Name}(2), exc.
rem | The overflow {Name}(1) protection was originally scripted by: michael_heath
FOR /R "%source%" %%i in (*.*) do (
If not exist "%target%\%%~nxi" (copy "%%i" "%target%") ELSE (call :index "%%~i" "%overflow%\%%~nxi" "1"))
rem | Run finished code here or end script with "goto :eof"
goto :eof
:index source, overflow, count
setlocal
set /a "cnt=%~3"
if exist "%overflow%\%~n2(%cnt%)%~x2" (
call :index "%~1" "%~2" "%cnt%+1"
) else copy "%~1" "%overflow%\%~n2(%cnt%)%~x2"

#echo off
setlocal
set "source=%cd%\source"
set "target=%cd%\target"
set "overflow=%cd%\overflow"
for /r "%source%" %%A in (*.*) do call :copyfile "%%~A" "move" "report"
2>nul rd "%source%"
exit /b
:copyfile source [, operation [, report]]
setlocal
set "curpath=%~1"
set "operation=%~2"
set "report=%~3"
if defined report echo "%curpath%"
call set "destpath=%%curpath:%source%=%target%%%"
if exist "%destpath%" call set "destpath=%%curpath:%source%=%overflow%%%"
if exist "%destpath%" (
if defined report echo exist in "%destpath%"
exit /b 1
)
if "%operation%" == "copy" (
if defined report echo copy to "%destpath%"
echo f|>nul xcopy "%curpath%" "%destpath%"
) else (
for %%A in ("%destpath%") do (
if not exist "%%~dpA" md "%%~dpA" || (
if defined report echo md failed with "%%~dpA"
exit /b 1
)
)
if defined report (
echo move to "%destpath%"
move "%curpath%" "%destpath%"
) else >nul move "%curpath%" "%destpath%"
for %%A in ("%curpath%") do 2>nul rd "%%~dpA"
)
exit /b 0
move on same partition is a move in the
master file table only.
move to different partition is an actual
copy and delete on successful copy.
copy always does copy.
I implemented both operations and can be set by the
2nd optional argument to the called label of :copyfile
by passing "move" or "copy".
"move" is default if argument is not "copy".
The 3rd optional argument to the label :copyfile
is to output a progress report.
This argument if defined, will echo information
(like paths etc.) about the operation.
The 1st argument to the label :copyfile is the
path to the file to be copied or moved.
The for /r loop recurses the source directory and
calls :copyfile with the path of each file found.
:copyfile will set curpath to the source file and
will set destpath to the path to target, which is
the source path substituted with target path.
If destpath exist, then destpath is set to the path
to overflow, which is the source path substituted
with overflow path. If still destpath exist, then
the label is exited.
The move operation uses rd to remove empty folders
from source.
The copy operation uses xcopy as it makes the
destination folder structure so that md is not used.
The echo f piped to xcopy is to answer the "file
or folder?" prompt.
At end of script, the source folder will be removed
if empty.
Set the source, target and overflow variables
at the top of the script to the actual paths.
View set /? about variable substitution used in
the script. It is used to replace the source
directory path with the another directory path,
to create the destination path.

Related

Compare Filenames from Two Different Folders and Delete the Matching File from Parent Folder Using Batch Script

I'm trying to compare filenames from two folders and delete if duplicate found from ParentFolder.
I'll explain bit more as follows,
Files I'm trying to process through batch script
ParentFolder
300103666600005_20221215T075949_0090002504.xml
300103666600003_20221215T075948_00900025054.xml
300103666600003_20221215T075977_0090002506223.xml
300103666600004_20221215T095950_009000250702.xml
And then the content modified files will be copied to a child folder(TargetFolder1) by adding _signed suffix at the end of the file name as shown below,
300103666600005_20221215T075949_0090002504_signed.xml
300103666600003_20221215T075948_00900025054_signed.xml
300103666600003_20221215T075977_0090002506223_signed.xml
300103666600004_20221215T095950_009000250702_signed.xml
What I was trying to do...
First copy the XML files which are not exists in the child folders.
Get the file name from ParentFolder without extension & assume it to a variable called match1
Get the file name from child folder without extension by omitting _signed & assume it to a variable called match2
Check whether match1 = match2. If so, delete that matching file from Source folder only. (Which means we already processed & signed this file and we no longer need unprocessed file in the ParentFolder)
Following is the code I used to achieve this,
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "ParentFolder=D:\Test\QGenV1"
set "TargetFolder1=D:\Test\QGenV1\ESIGN"
set "TargetFolder2=D:\Test\QGenV1\ECOMP"
if not exist "%SourceFolder1%\" echo ERROR: Missing source folder 1: "%SourceFolder1%"& goto ErrorExit
if not exist "%TargetFolder%\" echo ERROR: Missing source folder 2: "%SourceFolder2%"& goto ErrorExit
md "%TargetFolder1%" 2>nul
md "%TargetFolder2%" 2>nul
if exist "%TargetFolder1%\" goto Process
if exist "%TargetFolder2%\" goto Process
echo ERROR: Failed to create target folder: "%TargetFolder1%"
echo ERROR: Failed to create target folder: "%TargetFolder2%"
:ErrorExit
echo/
pause
exit /B 1
:Process
rem Copy all files being unique in ParentFolder to TargetFolder1.
for %%I in ("%ParentFolder%\*.xml") do (
if not exist "%TargetFolder2%\%%~nxI" COPY "%%I" "%TargetFolder2%\"
if not exist "%TargetFolder1%\%%~nxI" COPY "%%I" "%TargetFolder1%\"
)
rem Delete existing files
for /f "tokens=*" %%l in ("%ParentFolder%\*.xml") do (
set filename=%%~nl
echo From Parent !match1!
for /f "tokens=*" %%A in ("%TargetFolder1%\*.xml") do (
set filename2=%%~nA
echo From Target !match2!
if "!match2!" == "!match1!" DEL /F "%ParentFolder%\!match1!.xml"
)
)
pause
endlocal
What Happened & what went wrong?
Copying only the XML file from Parent folder to Child folders
(TargetFolder1 & TargetFolder2) - Success
Extracting Filename without extension - Success
Extracting Filename without _signed suffix from TargetFolder1 -
Success
Comparing & deleting the file from ParentFolder - Partially
successful. And that is the problem.
What do I mean by 'Partial success is that the deleting process only works until the first occurrence of a file delete happens. Iterating through remaining files to compare & delete process doesn't continue if the second comparison is unmatched.
Any help would be great...

Loop through files in a folder and check if they have different extensions

I have a folder that contains files; each document should have .pdf and .xml format. I need to write a BAT file to run from a scheduled task to verify that both documents exist for each.
My logic is:
loop through files in the folder
strip each file to its name without extension
check that same name files exist for both .xml and pdf.
if not mark a flag variable as problem
when done, if the flag variable is marked, send an Email notification
I know how to use blat to sending email, but I'm having trouble to execute the loop. I found a way to get path and file name without extension but can't merge them.
I've used batch files a few time, before but I'm far from an expert. What am I missing?
Here's the code I have so far:
set "FolderPath=E:\TestBat\Test\"
echo %FolderPath%
for %%f in (%FolderPath%*) do (
set /p val=<%%f
For %%A in ("%%f") do (
Set Folder=%%~dpA
Set Name=%%~nxA
)
echo Folder is: %Folder%
echo Name is: %Name%
if NOT EXIST %FolderPath%%name%.xml
set flag=MISSING
if NOT EXIST %FolderPath%%name%.pdf
set flag=MISSING
)
echo %Flag%
pause
There is no need for fancy code for a task such as this:
#Echo Off
Set "FolderPath=E:\TestBat\Test"
If /I Not "%CD%"=="%FolderPath%" PushD "%FolderPath%" 2>Nul||Exit/B
Set "flag="
For %%A In (*.pdf *.xml) Do (
If /I "%%~xA"==".pdf" (If Not Exist "%%~nA.xml" Set "flag=MISSING")
If /I "%%~xA"==".xml" (If Not Exist "%%~nA.pdf" Set "flag=MISSING")
)
If Defined flag Echo=%flag%
Timeout -1
Something like this :
set "FolderPath=E:\TestBat\Test\"
pushd "%FolderPath%"
for %%a in (*.xml) do (
if exist "%%~na.pdf"(
echo ok
) else (
rem do what you want here
echo Missing
)
)
popd
Is this what you want?
#echo off
setlocal enabledelayedexpansion
set "FolderPath=E:\TestBat\Test\"
echo !FolderPath!
for /f "usebackq delims=" %%f in (`dir !FolderPath! /B`) do (
set /p val=<%%f
For %%A in ("%%f") do (
Set Folder=%%~dpA
Set name=%%~nxA
)
echo Folder is: !Folder!
echo Name is: !name!
if NOT EXIST !FolderPath!!name!.xml set flag=MISSING
if NOT EXIST !FolderPath!!name!.pdf set flag=MISSING
)
echo Flag: !flag!
pause
endlocal
You should reformat your code and keep in mind that the grama for batch file is critical. BTW, if you are trying to update the existing batch variable and read it later, you should enable localdelayedexpansion and use ! instead of %.
Keep it simple:
#echo off
pushd "E:\TestBat\Test" || exit /B 1
for %%F in ("*.pdf") do if not exist "%%~nF.xml" echo %%~nxF
for %%F in ("*.xml") do if not exist "%%~nF.pdf" echo %%~nxF
popd
This returns all files that appear orphaned, that is, where the file with the same name but the other extension (.pdf, .xml) is missing. To implement a variable FLAG to indicate there are missing files, simply append & set "FLAG=missing" to each for line and ensure FLAG is empty initially. Then you can check it later by simply using if defined FLAG.
Note: This does not cover the e-mail notification issue. Since I do not know the BLAT tool you mentioned, I have no clue how you want to transfer the listed files to it (command line arguments, temporary file, or STDIN stream?).
In case there is a huge number of files in the target directory, another approach might be better in terms of performance, provided that the number of file system accesses is reduced drastically (note that the above script accesses the file system within the for loop body by if exist, hence for every iterated file individually). So here is an attempt relying on a temporary file and the findstr command:
#echo off
pushd "E:\TestBat\Test" || exit /B 1
rem // Return all orphaned `.pdf` files:
call :SUB "*.pdf" "*.xml"
rem // Return all orphaned `.xml` files:
call :SUB "*.xml" "*.pdf"
popd
exit /B
:SUB val_pattern_orphaned val_pattern_missing
set "LIST=%TEMP%\%~n0_%RANDOM%.tmp"
> "%LIST%" (
rem // Retrieve list of files with one extension:
for %%F in ("%~2") do (
rem /* Replace the extension by the other one,
rem then write the list to a temporary file;
rem this constitutes a list of expected files: */
echo(%%~nF%~x1
)
)
rem /* Search actual list of files with the other extension
rem for occurrences of the list of expected files and
rem return each item that does not match: */
dir /B /A:-D "%~1" | findstr /L /I /X /V /G:"%LIST%"
rem // Clean up the temporary file:
del "%LIST%"
exit /B
To understand how it works, let us concentrate on the first sub-routine call call :SUB "*.pdf" "*.xml" using an example; let us assume the target directory contains the following files:
AlOnE.xml
ExtrA.pdf
sAmplE.pdf
sAmplE.xml
So in the for loop a list of .xml files is gathered:
AlOnE.xml
sAmplE.xml
This is written to a temporary file but with the extensions .xml replaced by .pdf:
AlOnE.pdf
sAmplE.pdf
The next step is to generate a list of actually existing .pdf files:
ExtrA.pdf
sAmplE.pdf
This is piped into a findstr command line, that searches this list for search strings that are gathered from the temporary file, returning non-matching lines only. In other words, findstr returns only those lines of the input list that do not occur in the temporary file:
ExtrA.pdf
To finally get also orphaned .xml files, the second sub-routine call is needed.
Since this script uses a temporary file containing a file list which is processed once by findstr to find any orphaned files per extension, the overall number of file system access operations is lower. The weakest part however is the for loop (containing string concatenation operations).

How to execute an application existing in each specific folder of a directory tree on a file in same folder?

I have some folders with different names. Each folder has a specific structure as listed below:
Folder1
Contents
x64
Folder1.aaxplugin
TransVST_Fixer.exe
Folder 2
Contents
x64
Folder 2.aaxplugin
TransVST_Fixer.exe
There are two files within each subfolder x64. One file has the same name as the folder two folder levels above. The other file is an .exe file whose name is the same in all folders.
Now I need to run file with file extension aaxplugin on each specific .exe file. It would be obviously very time consuming opening each and every single folder and drag & drop each file on .exe to run it on this file.
That's why I am trying to create a batch script to save some time.
I looked for solutions here on Stack Overflow. The only thing I have found so far was a user saying this: When I perform a drag & drop, the process 'fileprocessor.exe' is executed. When I try to launch this exe, though, CMD returns error ('not recognized or not batch file' stuff).
How can I do this?
UPDATE 12/22/2015
I used first a batch file with following line to copy the executable into x64 subfolder of Folder1.
for /d %%a in ("C:\Users\Davide\Desktop\test\Folder1\*") do ( copy "C:\Program Files\Sugar Bytes\TransVST\TransVST_Fixer.exe" "%%a\x64\" 2> nul )
After asking here, I tried the following script:
for /f "delims=" %%F in ('dir /b /s x64\*.aaxplugin') do "%%~dpFTransVST_Fixer.exe" "%%F"
Unfortunately, the output is as following
C:\Users\Davide\Desktop>for /F "delims=" %F in ('dir /b /s x64\*.aaxplugin') do "%~dpFTransVST_Fixer.exe" "%F"
The system cannot find the file specified.
Try the following batch code:
#echo off
setlocal EnableDelayedExpansion
for /R "%USERPROFILE%\Desktop\test" %%F in (*.aaxplugin) do (
set "FilePath=%%~dpF"
if not "!FilePath:\x64\=!" == "!FilePath!" "%ProgramFiles%\Sugar Bytes\TransVST\TransVST_Fixer.exe" "%%F"
)
endlocal
The command FOR with option/R searches recursive in all directories of directory %USERPROFILE%\Desktop\test being expanded on your machine to C:\Users\Davide\Desktop for files with file extension aaxplugin. The loop variable F contains on each loop run the name of the found file with full path without surrounding double quotes.
The drive and path of each found file is assigned to environment variable FilePath.
Next a case-sensitive string comparison is done between file path with all occurrences of string \x64\ case-insensitive removed with unmodified file path.
Referencing value of environment variable FilePath must be done here using delayed expansion because being defined and evaluated within a block defined with ( ... ). Otherwise command processor would expand %FilePath% already on parsing the entire block resulting in a syntax error on execution because string substitution is not possible as no environment variable FilePath defined above body block of FOR loop.
The strings are not equal if path of file contains a folder with name x64. This means on provided folder structure that the file is in folder x64 and not somewhere else and therefore the application is executed next from its original location to fix the found *.aaxplugin file.
The line with IF is for the folder structure example:
if not "C:\Users\Davide\Desktop\test\Folder1\Contents" == "C:\Users\Davide\Desktop\test\Folder1\Contents\x64\"
if not "C:\Users\Davide\Desktop\test\Folder 2\Contents" == "C:\Users\Davide\Desktop\test\Folder 2\Contents\x64\"
So for both *.aaxplugin files the condition is true because the compared strings are not identical
Also possible would be:
#echo off
setlocal EnableDelayedExpansion
for /F "delims=" %%F in ('dir /A-D /B /S "%USERPROFILE%\test\*.aaxplugin" 2^>nul') do (
set "FilePath=%%~dpF"
if not "!FilePath:\x64\=!" == "!FilePath!" "%ProgramFiles%\Sugar Bytes\TransVST\TransVST_Fixer.exe" "%%F"
)
endlocal
But command DIR is not really necessary as it can be seen on first provided code.
But if the application TransVST_Fixer.exe for some unknown reason does its job right only with directory of file being also the current directory, the following batch code could be used instead of first code using the commands pushd and popd:
#echo off
setlocal EnableDelayedExpansion
for /R "%USERPROFILE%\test" %%F in (*.aaxplugin) do (
set "FilePath=%%~dpF"
echo !FilePath!
if /I "!FilePath:~-5!" == "\x64\" (
pushd "%%~dpF"
"%ProgramFiles%\Sugar Bytes\TransVST\TransVST_Fixer.exe" "%%~nxF"
popd
)
)
endlocal
There is one more difference in comparison to first code. Now the last 5 characters of path of file are compared case-insensitive with the string \x64\. Therefore the file must be really inside a folder with name x64 or X64. A folder with name x64 or X64 anywhere else in path of file does not result anymore in a true state for the condition as in first two batch codes.
But if for some unknown reason it is really necessary to run the application in same folder as the found *.aaxplugin and the directory of the file must be the current directory, the following batch code could be used:
#echo off
setlocal EnableDelayedExpansion
for /R "%USERPROFILE%\test" %%# in (*.aaxplugin) do (
set "FilePath=%%~dp#"
if /I "!FilePath:~-5!" == "\x64\" (
pushd "%%~dp#"
"%%~dp#TransVST_Fixer.exe" "%%~nx#"
popd
)
)
endlocal
The path of the file referenced with %%~dpF always ends with a backslash which is the reason why there is no backslash left of TransVST_Fixer.exe (although command processor could handle also file with with two backslashes in path).
In batch code above character # is used as loop variable because %%~dp#TransVST_Fixer.exe is easier to read in comparison to %%~dpFTransVST_Fixer.exe. It is more clear for a human with using # as loop variable where the reference to loop variable ends and where name of application begins. For the command processor it would not make a difference if loop variable is # or upper case F.
A lower case f would work here also as loop variable, but is in general problematic as explained on Modify variable within loop of batch script.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
dir /?
echo /?
endlocal /?
for /?
if /?
popd /?
pushd /?
set /?
setlocal /?
Your question isn't quite clear, but it seems, something like this should work:
for /f "delims=" %%f in ('dir /b /s X64\*.ext') do "%%~dpfMyExe.exe" "%%f"
Maybe you have to change directory to each folder (depends on your .exe):
for /f "delims=" %%d in ('dir /B /ad') do (
pushd "%%d"
for /f "delims=" %%f in ('dir /b "contents\x64\*.ext"') do (
cd Contents\x64
MyExe.exe "%%f"
)
popd
)
Assuming:
The Directory structure is fixed and the files are indeed in a subfolder contents\X64\.
MyExe.exe is the same (name) in every folder.
There is only one file *.ext in every folder.
I'll give you the script I created for doing so, hope it works for you
for /d %%d IN (./*) do (cd "%%d/Contents/x64" & "../../../TransVST_Fixer.exe" "%%d" & cd "/Program Files (x86)\Common Files\Avid\Audio\Plug-Ins")
Please note that I placed the fixer inside the root folder so I just have to copy it once. You have to place it inside your root folder and execute it. What it does:
iterate over each folder
for each one it enters /Contents/x64, executes the fixer (wich is 3 levels above) and after that returns to the original folder.
If you have your plugins in a different folder, you just have to change this part replacing the path for the one you have your plugins in.
cd "/Program Files (x86)\Common Files\Avid\Audio\Plug-Ins"
REMEMBER to place the script on that folder. For this example I place my script on the folder "/Program Files (x86)\Common Files\Avid\Audio\Plug-Ins" and run it (as a .bat).
PS: the fixer will place the fixed plugins in "C:\Users\Public\modified" (just read the screen while executing, it gives you the new files path. If you want to move them to the right path, you can execute this from the new files path ("C:\Users\Public\modified")
for %%d IN (*.aaxplugin) do (mkdir "%%d_temp/Contents\x64" & move "%%d" "%%d_temp/Contents\x64/%%d" & rename "%%d_temp" "%%d")
with that, I iterate over every plugin and create a folder with the same name (I create _temp because of name colision, after moving the file I rename it to the correct one), also with the subfolder "/Contents/x64", and move the plugin inside. Once donde, you can just take the resulting folders and place them in their correct path.
Hope it works, for me it works like a charm.

copy paste files using CMD

I want to accomplish the following: copy File A from Directory A to Directory B but File A already exist in Directory B and i don't want to overwrite it, simply put the new file in Directory B with a (1) or something so i'll know the difference. i can't manually name the file in the script as i plan to make it a batch file and run it every few hours therefore resulting in the same file existing with different names. IE. File A, File A(1), File A(2) so on and so on. please help. Thank you
Use Xcopy command with parameter /D
C:\> xcopy D:\source_dest E:\target_dest /E /D
/E parameter make that it copy files with subfolders
/D parameter make that it copy files without overwrite
if want more help inform me .if it works vote up
A cyclic copy refers to the situation where the source directory
contains the destination directory. Since the destination directory
is part of the source, the copying process eventually starts copying
the destination directory to a deeper portion of the destination.
This process will continue until, of course, the finite disk space
eventually runs out.
To avoid this condition but to achieve the objective, one can
specify a temporary destination which is on another volume (e.g.,
D:\temp\) and later copy the temporary destination to the final
destination, and delete the temporary directory at the end.
just check file exist before run xcopy command then run copy command
if NOT EXIST c:\directory B\File A ( xcopy c:\Directory A\File A c:\Directory B )
The following is made for folders but you can modify it for files.
Makes a backup of existed folder directory (and all contents in it) with new increase number in folder name [like TEST(1)... TEST(2)... folder].
The first part :Start will set the %PathFolder% variable with path to folder name (%userprofile%\Desktop\TEST) and then will search if exist. If NOT exists, will create it (xcopy), else, If exist, will directing the %PathFolder% variable to :Search label (for-)loop section for further handling...
Tip: Can be used %1 variable to set PathFolder set "PathFolder=%1" so it will work when you Drag-n-Drop a folder on this current saved batch file.
The second part :Search will search in the %PathFolder% variable (%userprofile%\Desktop\TEST) and will make a COPY of "TEST" folder (and all contents in it) with an increase number added in parenthesis at the end of folder name [like TEST(1)]. If already exist TEST(1) then will copy TEST folder as TEST(2) ... or TEST(3) ... and so on.
::Make a backup of existed folder directory (and all contents in it) with new increase number in folder name.
#echo off
setlocal EnableDelayedExpansion
set "IncrNum=1"
:Start
::The following will set the "%PathFolder%" variable with path to folder name (%userprofile%\Desktop\TEST) and then will search if exist. If NOT exists, will create it (xcopy), else, If exist, will directing the "%PathFolder%" variable to :Search label (for-)loop section for further handling...
::Tip: Can be used %1 instead of %userprofile%\Desktop\TEST in [set "PathFolder=..."] line so it will work when you Drag-n-Drop a folder on this current saved batch file.
set "PathFolder=%userprofile%\Desktop\TEST"
if NOT exist "%PathFolder%" (
xcopy %PathFolder% %PathFolder% /i /y
exit /b
) else (
goto :Search
)
exit /b
:Search
::The following will search in the "%PathFolder%" variable (%userprofile%\Desktop\TEST) and will make a COPY of "TEST" folder (and all contents in it) with an increase number added in parenthesis at the end of folder name [like TEST(1)]. If alredy exist TEST(1) then will copy TEST folder as TEST(2) ... or TEST(3) ... and so on.
for /f "tokens=*" %%G in ('dir /b /s /a:d "%PathFolder%*"') do (
if exist %%G^(%IncrNum%^) (
echo At "%%~dpG" a folder "%%~nG(%IncrNum%)" alredy existed.
set /a IncrNum+=1
goto :Search
) else (
echo.
echo.
echo The "%%~nG" folder and all contents in it
echo will be copied now as "%%G(%IncrNum%)".
echo.
pause
xcopy %%G %%G^(%IncrNum%^) /i /y
exit /b
)
)
:EndBatch
set "PathFolder="
pause
exit

How to create flat directory from folder hierarchy and handle duplicate files?

I want to parse a directory and its subdirectories and copy all files in a target directory ignoring the original folder structure. All files shall be copied directly in the target directory.
I found a nice solution here for the Windows command line:
for /r FolderA %f in (*) do #copy "%f" target
https://stackoverflow.com/a/1502183/772434
That in general works fine, but I have duplicate files in the source directory which have the same name. There are too many files, so I can not handle those exceptions by hand.
How can I handle those files in the script automatically?
Options:
overwrite files during copying
keep copies and rename file e. g. by adding "__123" a number at the end of the file name
compare files (MDS5 sum or similar) and create copy only if files are different.
I would prefer option 3 (compare file content and keep numbered copies only if files are really different), but I'm also interested in solutions for options 1 and 2 (more pragmatic).
Here's an approach. i haven't tested it, so i hope it works as expected.
There is a global variable called CURRENT_DUPLICATE_SUFFIX. every time a file with the same name is found, but with different content, this value gets incremented and appended to the resulting file name
#echo off
SET SOURCE_DIR=C:\temp\LogAnalyzer
SET TARGET_DIR=C:\temp\test\output
SET CURRENT_DUPLICATE_SUFFIX=1
for /r "%SOURCE_DIR%" %%f in (*) do CALL :SUB1 "%%f"
GOTO END
:SUB1
SET PURE_FILE_NAME=%~nx1
SET TARGET_FILE_NAME=%TARGET_DIR%\%PURE_FILE_NAME%
IF NOT EXIST "%TARGET_FILE_NAME%" (
COPY %1 "%TARGET_DIR%"
GOTO :EOF
)
REM if we are here, the target file exists.
echo n |comp %1 "%TARGET_FILE_NAME%" >NUL 2>NUL
REM in case the files have the same content
IF %ERRORLEVEL%==0 GOTO :EOF
SET TARGET_FILE_NAME=%TARGET_FILE_NAME%_%CURRENT_DUPLICATE_SUFFIX%
SET /A CURRENT_DUPLICATE_SUFFIX=%CURRENT_DUPLICATE_SUFFIX%+1
COPY %1 "%TARGET_FILE_NAME%
GOTO :EOF
:END

Resources