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

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

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...

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

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.

Bat script to find and replace files in multiple subfolders - replace .java files with .class files from specific folder

I am new to windows batch scripting .. please help on this scenario
I have file structures as below ::
dir1:
c:\workspace\changeset\com\folder
subfolder1
one.java
subfolder-2
two.java
dir2:
c:\workspace\target\class\com\folder
subfolder1
one.class
subfolder2
two.class
Subfolder3
three.class
Need to find and replace dir1 files in respective subfolders i.e one.java and two.java from dir2 files i.e one.class and two.class ( need to replace certain .java files with .class files from specific folder )
much appreciated for your help.
Thanks
Arjun
for /f "delims=" %%a in ('dir /b /a-d "c:\workspace\changeset\com\folder\*.java"') do (
if exist "c:\workspace\target\class\com\folder\%%~na.class" (
echo copy "c:\workspace\target\class\com\folder\%%~na.class" "c:\workspace\changeset\com\folder\%%a")
)
The required COPY commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO COPY to COPY to actually copy the files. Append >nul to suppress report messages (eg. 1 file copied)
Note that execution directly from the prompt and as lines with a batch file are different. The metavariable (loop-control variable) %%x must be referenced as %%x for a batch line and %x if executed from the command prompt. Since it makes little sense to repeatedly execute a line containing a for from the prompt (it's easier to create a batch file), I post the batch-file version. User's responsibility to adjust for direct-from-prompt if desired.
Read each filename in /b basic form /a-d without directories and assign the filename+extension to %%a.
If a file in the other directory called thenamepartofthefile.class exists, then copy that file to the first directory.
Please post the entire problem to be solved. The approach can change radically, as in this case.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir1=U:\sourcedir\changeset"
SET "sourcedir2=U:\sourcedir\target"
FOR /f "delims=" %%a IN (
'dir /b /s /a-d "%sourcedir1%\*.java" '
) DO (
SET "javadir=%%~dpa"
SET "classfile=!javadir:%sourcedir1%=%sourcedir2%!%%~na.class"
IF EXIST !classfile! ECHO COPY "!classfile!" "%%a"
)
GOTO :EOF
You would need to change the settings of sourcedir1 and sourcedir2 to suit your circumstances.
Essentially, the same approach and the same comments re messages. The difference is that this procedure uses files and subdirectories in the dir list and substitutes the first part of the directoryname in deriving the expected name of the .class file.

Batch Function Not Copying Properly

REM Capture the date/time(right down to the second) and then assign it to a variable
set yy=%date:~-4%
set dd=%date:~-7,2%
set mm=%date:~-10,2%
set newdate=%dd%%mm%%yy%_%Time:~0,8%
set newdate=%newdate::=%
SET foldername="svetlana_backup_%newdate%"
SET drive=T:
REM Source directories
SET documents=%drive%\Documents
REM Destination directories
SET destinationDocuments=%backupDir%\Documents
call:makedirandcopy %documents% %destinationDocuments%
:makedirandcopy
ECHO Making and Copying %~2 Directory
MKDIR %~2
XCOPY %~1 %~2 /E /F
I have the following batch file on my desktop, when I run the batch file, it supposed to make a directory on my destination drive and copy all the documents, however, it makes the directory, and the documents subdirectory, but on my desktop, where the batch file resides, and never copies the files in Documents. The file name is also incorrect, it just assigns the time to the directory instead of the date_time.
Passing T:\Documents "T:\Backup"\"svetlana_backup_23022016_ 91300"\Documents
Making and Copying T:\Backup"\"svetlana_backup_23022016_ 91300"\Documents Directory
Making and Copying Directory
0 File(s) copied
If I were to do all of this without the label it works.
call :makedirandcopy %documents% %destinationDocuments%
goto :EOF
:makedirandcopy
ECHO Making and Copying %~2 Directory
MKDIR "%~2"
XCOPY "%~1" "%~2" /E /F
goto :EOF
From your run report, you have a line
Passing T:\Documents "T:\Backup"\"svetlana_backup_23022016_ 91300"\Documents
There is nothing in the code you've posted that will generate that line.
You then have
Making and Copying T:\Backup"\"svetlana_backup_23022016_ 91300"\Documents Directory
Making and Copying Directory
The cause of this is that you are calling :makedirandcopy (which displays the first line) and when the called routine ends (presumably it reaches end-of-file) control is returned to the statement following the call - which is the routine again, this time with no parameters, hence the second line.
Try
call :makedirandcopy "%documents:"=%" "%destinationDocuments:"=%"
goto :EOF
which will remove the excess quotes in each of the variables and quote the result.
Note that since there are spaces in the parameters being passed to :makedirandcopy, xcopy will require those parameters quoted.
Perhaps you'd also need
...
set newdate=%newdate::=%
set newdate=%newdate: =0%
...
to replace the suppressed-leading-zero in the time with a real, genuine 0.

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

Resources