I have many folders of images, and I want to create a batch file that can look through all these directories and their subdirectories, and copy every image to a single new folder (all files in the same folder). I have this working using the below:
md "My new folder"
for /D %i in (*) do copy "%i\*" ".\My New Folder"
however, I also want to keep files with duplicates (for example if folder1 and folder2 both have images called 001.jpg, i want both copied to the new folder). It doesn't matter to me what the new filenames are! Having:
001.jpg
001(1).jpg
001(2).jpg
would be great, but even just renaming every single file with an incremental count and ending up with:
1.jpg
2.jpg
3.jpg
etc
would be fine too. I need it just using a standard .bat/.cmd file though, no external software.
Thanks for your help!
This should work for you. It appends a number after the extension, but you could easily move that anywhere. I copied files from the .\src dir, since if you have the sources at the same level as the batch file, the batch file tries to evaluate test_folder too. The best choice would be to hardcode test_folder so it is somewhere that won't be evaulated by the DIR /S /B... command
@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set TESTFOLDER=test_folder
md "%TESTFOLDER%"
set /a counter=0
FOR /F "tokens=*" %%i IN ('DIR /S /B /A-D .\src\*') DO FOR /F "tokens=*" %%j IN ('DIR /B "%%i"') DO IF EXIST ".\%TESTFOLDER%\%%j" (
set /a counter=!counter!+1
echo folder: %TESTFOLDER%
copy "%%i" ".\%TESTFOLDER%\%%j_!counter!"
) ELSE copy "%%i" ".\%TESTFOLDER%\%%j"
:eof
The following script is an improved version of aflat's answer.
The script expects two arguments: SourcePath TargetPath.
It recursively copies all files from SourcePath and its subfolders to TargetPath, appending an increasing counter to the base name only if there is a duplicate.
It errors out if the TargetPath already exists because there may already exist names with the _n suffix.
More work is needed if you want a separate counter for each base name and/or if you want to be able to copy to an existing folder.
The script is more robust than the aflat answer. For example, names with !
work just fine. It also implements aflat's algorithm in a more direct and more efficient way.
::copyFlat sourcePath TargetPath
@echo off
setlocal disableDelayedExpansion
:: Initialize and validate arguments
if "%~2" equ "" echo Error: Insufficient arguments>&2&exit /b 1
set "source=%~f1"
if not exist "%source%\" echo Error: Source folder "%source%" does not exist>&2&exit /b 1
set "target=%~f2"
if exist "%target%\" echo Error: Target folder "%target%" already exists>&2&exit /b 1
:: Do the work
md "%target%"
set /a n=0
for /r "%source%" %%F in (*) do if "%%~dpF" neq "%target%\" (
if exist "%target%\%%~nxF" (
set /a n+=1
set "full=%%F"
set "name=%%~nF"
set "ext=%%~xF"
setlocal enableDelayedExpansion
copy "!full!" "!target!\!name!_!n!!ext!" >nul
endlocal
) else copy "%%F" "%target%" >nul
)
Or you can install git bash (https://git-for-windows.github.io/) and run the following:
mv --backup=numbered src\*.* destinationFolder
This will create files that look like filename.ext.~1~, filename.ext.~2~ ...
This may be enough for you, in my case I didn't like losing the original file extension so you can rename that by running the below in the destination folder:
ls *~ | sed 's/\(.*\)\.\(.*\)\.~\(.*\)~/mv -i & \1.\3.\2/'
This will print the rename commands like so:
mv filename.ext.~1~ filename.1.ext
Once you are happy that you want to execute these commands, run the same command again but pipe to sh to be executed like so (be aware any existing files the same as the final rename will be overwritten - but the -i option should protect you):
ls *~ | sed 's/\(.*\)\.\(.*\)\.~\(.*\)~/mv -i & \1.\3.\2/' | sh
Adapted from this answer (https://stackoverflow.com/a/2372739)