Batch How to avoid a same 2nd FOR loop? - windows

I have created a batch script to backup some subfolders from a path A to a path B (Z:\Folder1\… > U:\Backup\…).
The script lists the subfolders inside path A and increments a number for each of them.
Then, I just have to enter the number(s) of the subfolder(s) I want to backup and xcopy does the rest.
The problem is that sometimes I have thousands of subfolders in path A and only a few to backup (10 or 15).
What I would like is that once I enter the number of these folders, it will go straight to the backup without having to loop all the subfolders inside path A AGAIN (which take time).
Here is my batch :
#echo off
setlocal EnableDelayedExpansion
rem Script for backuping some subfolders from path A to path B
set BackupLocation=U:\Backup
set subfolder_no=1
FOR /F "delims=" %%a IN ('dir /b "Z:\Folder1\*"') DO (
set subfolder=%%a
if defined subfolder (
echo !subfolder_no! !subfolder!
set /a subfolder_no+=1
)
)
set /a subfolder_no=%subfolder_no%-1
set /a index=0
set /a choice=-1
echo.
set /p choice=Enter the number(s) of the subfolder(s) you want to backup:
FOR /F "delims=" %%a IN ('dir /b "Z:\Folder1\*"') DO (
set subfolder=%%a
if defined subfolder (
set /a index+=1
)
FOR %%f IN (%choice%) DO if %%f==!index! (
echo.
echo Backuping subfolder !subfolder!
xcopy "Z:\Folder1\!subfolder!" "%BackupLocation%\!subfolder!\" /e /i /y
)
)
echo.
pause
exit
How can I do this ? Is it possible to get the subfolders' name from their matching number and store them in variables or something ?
Thanks a lot for your help !

Here's an example which only enumerates the directories once.
Please note, whilst it technically answers your question, and performs the task you require of it, this version is designed to work as intended on Windows 10. The specific part you asked about works in other versions too, but the :BackUp labelled section uses a new and undocumented Windows 10 feature of the sort command, to return only unique items from the selection list. Without that, your end user could tehnically provide the same number multiple times, and thus trigger multiple backups of the same directory. As this part of the code is technically outside of the scope of your question, I will leave it up to you to modify the code section yourself, should you be deploying this on older Operating Systems.
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Rem Script for backing up some subdirectories of a Source path to a Backup path.
Set "SourceLocation=Z:\Folder1"
Set "BackupLocation=U:\Backup"
If Not Exist "%Sourcelocation%\." Exit /B
If Not Exist "%Backuplocation%\." Exit /B
:ShowSet
For /F "Delims==" %%G In ('"(Set subdirectory[) 2>NUL"') Do Set "%%G="
Set "index=0"
For /F "EOL=? Delims=" %%G In ('Dir /B /A:D /O:N "%SourceLocation%" 2^>NUL'
) Do (Set /A index += 1
Set "subdirectory=%%G"
SetLocal EnableDelayedExpansion
Echo !index! !subdirectory!
For /F "Tokens=1,*" %%H In ("!index! !subdirectory!") Do (EndLocal
Set "subdirectory[%%H]=%%I"))
If Not Defined subdirectory[1] Exit /B
:Select
Echo(
Echo Please type the number(s) for the subdirectories you want to backup,
Echo(
Echo For multiple selections please separate each with spaces e.g. 1 3 6
Echo For none please type 0 or press [ENTER].
Set "selection=0"
Set /P "selection=>"
Set "selection=%selection:"=%"
Set "selection=%selection:)=%"
If Not Defined selection GoTo Select
If "%selection%" == "0" GoTo :EOF
(Set selection) | "%SystemRoot%\System32\findstr.exe"^
/X /R /C:"selection=[0123456789 ][0123456789 ]*" 1>NUL || GoTo Select
Set "selection=%selection% "
:BackUp
For /F %%G In (
'"(Echo(%selection: =^&Echo(%) | "%SystemRoot%\System32\sort.exe" /Unique"'
) Do If Not Defined subdirectory[%%G] (Echo Selection %%G was not valid) Else (
SetLocal EnableDelayedExpansion
Echo(&Echo Backing up subdirectory %%G !subdirectory[%%G]!
"%SystemRoot%\System32\Robocopy.exe" ^
"%SourceLocation%\!subdirectory[%%G]!" ^
"%BackupLocation%\!subdirectory[%%G]!" /E /NC /NDL /NJH /NJS /NS ^
| %SystemRoot%\System32\find.exe /V " (0x00000005) "
EndLocal)
Pause
In the :BackUp section, I have used Robocopy.exe instead of the deprecated xcopy.exe utility you had used.
If you wish to still use xcopy.exe, replace:
"%SystemRoot%\System32\Robocopy.exe" ^
"%SourceLocation%\!subdirectory[%%G]!" ^
"%BackupLocation%\!subdirectory[%%G]!" /E /NC /NDL /NJH /NJS /NS ^
| %SystemRoot%\System32\find.exe /V " (0x00000005) "
with:
"%SystemRoot%\System32\xcopy.exe" ^
"%SourceLocation%\!subdirectory[%%G]!" ^
"%BackupLocation%\!subdirectory[%%G]!\" /E /I /Y

Related

How to rename only sub-folders without changing parent folder names

I have a folder containing several hundred sub-folders in the format Name, ID. Each of these folders contain several sub folders, some of which contain spaces in their names. I would like to rename only the sub folders and not the parent folders by replacing the spaces with underscores, e.g. C:\Location\John, 1234\My Documents to C:\Location\John, 1234\My_Documents.
I have tried modifying a piece of script I have found on here but it changes the parent folder as well
Here is the unedited code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "StartFolder=C:\Tydelik"
cd /D %SystemRoot%
set "RenameError="
rem Rename all folders containing at least one space character in folder name.
for /F "delims=" %%I in ('dir "%StartFolder%\* *" /AD /B /S 2^>nul') do call :RenameFolder "%%I"
if defined RenameError echo/& pause
rem Restore initial environment and exit this batch file.
endlocal
goto :EOF
:RenameFolder
set "NewFolderName=%~nx1"
set "NewFolderName=%NewFolderName: =_%"
set "FolderPath=%~dp1"
if not exist "%FolderPath%" set "FolderPath=%FolderPath: =_%"
set "FullFolderName=%FolderPath%%~nx1"
if not exist "%FullFolderName%\" set "RenameError=1" & goto :EOF
for %%J in ("%FullFolderName%") do set "FolderAttributes=%%~aJ"
if "%FolderAttributes:~3,1%" == "h" %SystemRoot%\System32\attrib.exe -h "%FullFolderName%"
ren "%FullFolderName%" "%NewFolderName%" 2>nul
if errorlevel 1 goto ErrorFolderRename
if "%FolderAttributes:~3,1%" == "h" %SystemRoot%\System32\attrib.exe +h "%FolderPath%%NewFolderName%"
goto :EOF
:ErrorFolderRename
echo Error renaming folder "%FullFolderName%"
set "RenameError=1"
if "%FolderAttributes:~3,1%" == "h" %SystemRoot%\System32\attrib.exe +h "%FullFolderName%"
goto :EOF
As I said the expected output for each sub folder should be C:\Location\John, 1234\My_Documents instead of C:\Location\John, 1234\My Documents. Currently with the code I have, I get C:\Tydelik\John,_1234\My_Documents.
While Compo's solution renames folders "depth=2", this renames just the "leafes" (very last folders of a tree, "depth=last"). I kept your call approach to avoid delayed expansion and resulting possible problems (folder names with ! - unlikely in your situation, but one never knows...)
#echo off
setlocal
set "sourcedir=..\..\"
for /f "delims=" %%I in ('dir "%sourcedir%" /ad /b /s 2^>nul') do call :RenameFolder "%%I"
goto :eof
:RenameFolder
dir /ad /b /s "%~1" 2>nul | find /v "" >nul && goto :eof ::skip renaming, if a subfolder exists
set "leaf=%~nx1"
ECHO ren "%~1" "%leaf: =_%"
goto :eof
Note: for security reasons I disabled the ren command by just echoing it. If it works as intended, remove the ECHO.
Here's an example of what I think you're looking for, based upon the fact that you're interested only in renaming subdirectories of "C:\Tydelik\Name, ID", not any contained within those subdirectories:
#Echo Off
SetLocal DisableDelayedExpansion
Set "SourceDir=C:\Tydelik"
For /F "EOL=?Delims=" %%A In ('Dir /B/AD "%SourceDir%" 2^>NUL'
)Do Set "TargetDir="&For /F "EOL=?Delims=" %%B In (
'Dir /B/AD "%SourceDir%\%%A" 2^>NUL') Do (Set "TargetDir=%%B"
SetLocal EnableDelayedExpansion
If Not "!TargetDir: =!"=="!TargetDir!" (
Ren "%SourceDir%\%%A\%%B" "!TargetDir: =_!")
EndLocal)

copy folders with files with a batch program (Windows)

I am blocked in an exercise... We have the next structure:
1) company/companyA/1.KYC/data17-07-05.xls
2) company/companyB/1.KYC/data17/08/04.xls
3) company/companyC/1.KYC/data17/08/08.xls & docXLS.xls
4) etc.
I would like to copy only the folders number 1 and 2 and not the 3... (so only folders where we have 1 file and not 2).
I don't have the idea of how I have to begin...
I have the next code but I am lost:
#echo off
setlocal disabledelayedexpansion
set "folder=%~1"
if not defined folder set "folder=C:\Users\Albert\Desktop\backup2\company01\"
for /d %%a in ("%folder%\*") do (
set "size=0"
for /f "tokens=3,5" %%b in ('dir /-c /a /w /s "%%~fa\*" 2^>nul ^| findstr /b /c:" "') do if "%%~c"=="" set "size=%%~b"
setlocal enabledelayedexpansion
if !size! GTR 0 xcopy "C:\Users\Albert\Desktop\backup2\company01\"%%~nxa "C:\Users\Albert\Desktop\backup2\"%%~nxa /e /i
echo(%%~nxa # !size!
endlocal
)
pause
I am a beginner in the batch langage so if it's possible to help me .. Thank a lot !
The following assumes, as per your specified data, that the .xls files will always be in a sub directory named 1.KYC:
#Echo Off
SetLocal DisableDelayedExpansion
Set "folder=%~1"
If Not Defined folder Set "folder=%UserProfile%\Desktop\backup2\company01"
If Not Exist "%folder%\" Exit/B
For /F "Delims=|" %%A In ('Dir/B/S/AD-S-L "%folder%\1.KYC"') Do (Set "_="
For /F "Skip=6Tokens=3" %%B In ('RoboCopy/L /NFL /NDL /NJH "%%A" Null *.xls'
) Do If "%%B"=="1" If Not Defined _ (Set "_=T"
XCopy "%%A" "%UserProfile%\Desktop\backup2\%%~nxA" /E /I))
It does however have a known issue:The RoboCopy command will match any file extensions beginning with .xls which means if you wanted it to match a directory containing only one .xls file but there was also an .xlsx file in there, it will not function as you need.

BATCH Comparing two folders recursively

i'm updating a big save script and i need to compare 2 folders recursively. I think i'm pretty close but can't understand what's missing...
The code is the following :
set Rep1=f:\album1
set Rep2=f:\album2
set logfile=f:\logfile.txt
for /r "%Rep1%\" %%i in (*) do (
fc "%%i" "%Rep2%\%%~nxi"
iF ERRORLEVEL == 1 echo "%%i" et "%Rep2%\%%~nxi" Sont differents >> %logfile%
iF ERRORLEVEL == 2 echo "%%i" et "%Rep2%\%%~nxi" Un des fichier est manquant >> %logfile%
)
pause
The problem is that it compares all files like f:\album1\folder1\file1.txt with f:\album2\file1.txt so the comparing is always wrong... You can see the result in the picture:
If any of you find a solution, thank you a lot !
Vincs
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "targetdir=U:\destdir"
FOR /f "delims=" %%a IN (
'dir /s /b /a-d "%sourcedir%\*" '
) DO (
SET "foundfile="
FOR /f "delims=" %%c IN (
'dir /s /b /a-d "%targetdir%\%%~nxa" 2^>nul'
) DO (
SET foundfile=Y
FC /b "%%a" "%%c" >NUL
IF ERRORLEVEL 1 ECHO different "%%a" "%%c"
)
IF NOT DEFINED foundfile ECHO missing "%%a" from "%targetdir%"
)
FOR /f "delims=" %%a IN (
'dir /s /b /a-d "%targetdir%\*" '
) DO (
SET "foundfile="
FOR /f "delims=" %%c IN (
'dir /s /b /a-d "%sourcedir%\%%~nxa" 2^>nul'
) DO (
SET foundfile=Y
)
IF NOT DEFINED foundfile ECHO missing "%%a" from "%sourcedir%"
)
GOTO :EOF
You would need to change the settings of sourcedir and targetdir to suit your circumstances.
One problem with your approach is that the file %%i is compared to "%Rep2%\%%~nxi" which means only in %rep2%, not in the subdirectory.
Another problem is
IF ERRORLEVEL == 1 echo "%%i" et "%Rep2%\%%~nxi" Sont differents >> %logfile%
which compares the literal string ERRORLEVEL to the literal string 1 so will not find a match. To use your method, you would have to turn delayedexpansion on with a setlocal enabledelayedexpansion statement and then use IF !ERRORLEVEL!==1 ...
The solution posted above compares files that have the same name and extension wherever they are found on the tree, so if file1.txt is anywhere in the first tree, then it will be compared to all the file1.txt files found anywhere in the second tree.
Note also that there is a standard anomaly when dealing with a standard system that gives files both a long and a short name. Each file potentially has two names - and dir matches on either name.
Magoo's answer already points out the major problems of your code.
However, the solution he provided uses only the file names for finding the files to compare, so it will fail if files with equal names occur at different locations in the source and target directories, or if multiple files with equal names occur within any of the directory trees.
Here is a similar solution, based on the dir /S command, which also requires each file name in the trees to be unique and to occur at the same location within source and target (it does not check for files present in only one of the source or target trees):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Provide source and target directory paths here:
set "SOURCE=.\source"
set "TARGET=.\target"
rem Convert relative paths to absolute ones:
for %%D in ("%SOURCE%") do set "SOURCE=%%~fD"
for %%D in ("%TARGET%") do set "TARGET=%%~fD"
for /F "eol=| delims=" %%I in ('
2^> nul dir /B /S /A:-D "%SOURCE%\*.*"
') do (
set "SRC=%%~fI"
for /F "eol=| delims=" %%J in ('
2^> nul dir /B /S /A:-D "%TARGET%\%%~nxI"
') do (
set "TRG=%%~fJ"
setlocal EnableDelayedExpansion
> nul fc /B "!SRC!" "!TRG!" || echo "!SRC!" and "!TRG!" differ.
endlocal
)
)
endlocal
exit /B
This code snippet compares only files which occur in both source and target directory trees. If respective files are different, a related message is returned.
To overcome the issue with equal file names at different locations, let us use the xcopy /L command, because this is capable of returning a list of paths relative to the source directory (the /L option prevents xcopy from copying any files; the appended find command filters out the ? File(s) summary lines):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Provide source and target directory paths here:
set "SOURCE=.\source"
set "TARGET=.\target"
rem Convert relative paths to absolute ones:
for %%D in ("%SOURCE%") do set "SOURCE=%%~fD"
for %%D in ("%TARGET%") do set "TARGET=%%~fD"
pushd "%SOURCE%"
for /F "eol=| delims=" %%I in ('
2^> nul xcopy /L /S /Y ".\*.*" "%TEMP%\" ^| find ".\"
') do (
set "SRC=%%~fI"
pushd "%TARGET%"
for /F "eol=| delims=" %%J in ('
2^> nul xcopy /L /Y "%%~I" "%TEMP%\" ^| find ".\"
') do (
set "TRG=%%~fJ"
setlocal EnableDelayedExpansion
> nul fc /B "!SRC!" "!TRG!" || echo "!SRC!" and "!TRG!" differ.
endlocal
)
popd
)
popd
endlocal
exit /B
This code snippet also compares only files which occur in both source and target directory trees. If you also want to check whether each fils is present in both source and target trees, check out Magoo's answer which provides a good idea of how to accomplish that (two-loop approach).

batch file to count all files in a folder and subfolder files and write output file in folder name using batch file

How to count files in a folder and subfolder files also. folder name and file count and sub folder name and file count.
Ex:
test1 : 2
test1\test11 :3
newfolder : 5
newfolder : 10
like this.
robocopy "x:\target\folder" "x:\target\folder" /l /nocopy /is /e /nfl /njh /njs
or
pushd "x:\target\folder" && (
robocopy . . /l /nocopy /is /e /nfl /njh /njs
popd
)
This will simply call robocopy, but instead of copying anything, we will request that nothing will be copied and only return the list of what should be processed (/nocopy /l). We request to copy from the current folder (a previous pushd command is used) to the current folder, including identical files in the process (/is), processing empty subfolder (/e, to include folders with 0 files), but only process two levels (/lev:2 the current folder and the one below), without generating a file list (/nfl), no job header (/njh) and no job summary (/njs)
The result will be the same list but with the folder name and the number of files in changed columns
To keep the original output format
#echo off
setlocal enableextensions disabledelayedexpansion
pushd "x:\target\folder" && (
for /f "tokens=1,*" %%a in ('
robocopy . . /l /nocopy /is /e /nfl /njh /njs
') do echo %%~fb : %%a
popd
)
This will use a for /f to process the previous robocopy command, splitting the line in two tokens, the first will contain the number of files and will be stored in %%a, and the second the rest of the line and will be stored in %%b. For each line in the output of the inner robocopy command, the code in the do clause is executed: just echo to console the two tokens in reverse order.
If robocopy can not be used (OS older than Vista), then
#echo off
setlocal enableextensions disabledelayedexpansion
for /d /r "x:\target\folder" %%a in (*) do for /f "tokens=1,5" %%b in ('
dir /a-d "%%~fa.\*" 2^> nul ^| findstr /b /c:" " ^|^| echo 0
') do if "%%c"=="" echo %%~fa : %%b
This will
For each folder under the start directory (for /r /d) grab a reference and store it in %%a replaceable parameter
Run a dir command with the full path of the folder %%~fa
Use a pipe (|) to filter the list to only retrieve the lines that start with two spaces (the footer lines)
If no lines are found (that is, the dir command failed) output a 0
The lines generated by the dir | findstr are handled with a for /f command. We will read the first token (the number of files in the adecuated line) and the fifth (only present in the footer line with the directories info)
If the fifth element is empty, this line has information about the files, not the folders, so, echo the folder path and the files inside it
At the end, restore the previous active directory
The problem with this approach is that the dir | findstr is executed for each of the subfolders. This will make this slower than the robocopy solution.
It can be faster, but more code is needed
#echo off
setlocal enableextensions disabledelayedexpansion
set "root=%cd%"
set "folder="
for %%r in ("%root%") do (
set "rootDrive=%%~dr\"
if not defined rootDrive set "rootDrive=\\"
for /f "delims=" %%a in ('
dir /s /a "%%~fr.\*" 2^>nul ^| findstr /r /c:"^ " /c:"^ .*\\."
') do for /f "tokens=1,* delims=\" %%b in ("%%~a") do if not "%%c"=="" (
set "folder=%%c"
) else if defined folder (
for /f %%d in ("%%~a") do (
setlocal enabledelayedexpansion
echo(!rootDrive!!folder! : %%d
endlocal
)
set "folder="
)
)
In this case, we will execute only one dir command to retrieve the full list and filter with findstr the list to only retrieve the lines with the name of the folder and the footer for each folder.
The code will iterate (for /f %%a) over this list. When a folder line is found (it contains a backslash and can be splitted by the for /f %%b), the folder name is saved in a variable. When the corresponding footer line is readed (it was not splitted by a backslash), the line is splitted to get the number of files (for /f %%d) and the folder name and the number of files are echoed to console (here delayed expansion is needed to retrieve the variable contents, as they were set inside the same loop)
Note: Using a for /f to process a large list of data generated by executing a command can be really slow (there is a bad behaviour in how the command handles memory). For this cases it is necessary to first execute the command that generates the data (dir | findstr in this case) sending its output to a file and then use the for /f to process the file.
#echo off
setlocal enableextensions disabledelayedexpansion
set "root=%~1"
if not defined root for %%a in (.) do set "root=%%~fa"
set "folder="
for %%t in ("%temp%\%~nx0.%random%%random%.tmp") do for %%r in ("%root%") do (
set "rootDrive=%%~dr\"
if not defined rootDrive set "rootDrive=\\"
( dir /s /a "%%~fr.\*" 2^> nul | findstr /r /c:"^ " /c:"^ .*\\." ) > "%%~ft"
for /f "usebackq delims=" %%a in ("%%~ft") do (
for /f "tokens=1,* delims=\" %%b in ("%%~a") do if not "%%c"=="" (
set "folder=%%c"
) else if defined folder (
for /f %%d in ("%%~a") do (
setlocal enabledelayedexpansion
echo(!rootDrive!!folder! : %%d
endlocal
)
set "folder="
)
)
del /q "%%~ft"
)
edited to adapt to comments: robocopy solution changed to include total number of files
#echo off
setlocal enableextensions disabledelayedexpansion
set "total=0"
pushd "x:\target\folder" && (
for /f "tokens=1,*" %%a in ('
robocopy . . /l /nocopy /is /e /nfl /njh /njs
') do (
echo %%~fb : %%a
set /a "total+=%%a"
)
popd
)
echo Total files: %total%

look for file of a certain type one subfolder down, sort by date modified (newest first), and display subfolder name (NOT filename) in sorted order

This is a very specific question, so I've separated it into 3 parts.
Look in all subfolders for a certain file: world.sav, but only 1 level down, i.e.
C:\workingdir\foo\world.sav
C:\workingdir\bar\world.sav
C:\workingdir\baz\world.sav
C:\workingdir\qux\world.sav
is fine, but
C:\workingdir\foo\bar\world.sav
C:\workingdir\world.sav
isn't, etc.
Sort these world.sav files by date modified (newest first).
Display the name of the subfolder each world.sav file is in, in the previously sorted order. i.e. if the above list was date-sorted into
C:\workingdir\qux\world.sav (newest)
C:\workingdir\bar\world.sav
C:\workingdir\foo\world.sav
C:\workingdir\baz\world.sav (oldest)
then the output would be
qux
bar
foo
baz
I've tried numerous methods involving DIR, FORFILES and manipulation of variables, but the 2 main problems I've come across so far are
Both commands mentioned above will arrange by subfolder, then by date, and I can't find a way to avoid it.
Date formatting. It appears to be different for every localization of Windows, and I really want this to be locale-independent.
Also, it must support spaces in folder names.
EDITED version with a wait message:
#echo off
echo Please wait...
cd /d "c:\workingdir"
(for /d %%a in (*) do #robocopy "%%a" "%%a" world.sav /L /nocopy /is /njh /njs /ndl /nc /ns /ts)|(
#cls
for /f "tokens=2*" %%b in ('sort /r') do #for %%z in ("%%~dpc\.") do #echo %%~nz
)
cd /d "%~dp0"
echo.
pause
original version below
This works here:
robocopy is used on each folder in the directory to generate a list (UTCdate time drv:\path\world.sav format) and that is sorted to get most recent at the top of the list, which the second for parses to extract the drv:\path\folder\world.sav and the last for loop prints out just the folder name.
#echo off
cd /d "c:\workingdir"
(for /d %%a in (*) do #robocopy "%%a" "%%a" world.sav /L /nocopy /is /njh /njs /ndl /nc /ns /ts)|for /f "tokens=2*" %%b in ('sort /r') do #for %%z in ("%%~dpc\.") do #echo %%~nz
pause
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET /a count=0
:: remove variables starting $
FOR /F "delims==" %%a In ('set $ 2^>Nul') DO SET "%%a="
FOR /f "delims=" %%a IN (
'dir /b /ad "%sourcedir%\*" '
) DO IF exist "%sourcedir%\%%a\world.sav" CALL :set$ "%%a"
IF %count%==0 ECHO No files found&GOTO :EOF
IF %count%==1 ECHO %$1%&GOTO :EOF
:sortol
SET /a start=1
SET /a swap=0
:sortil
CALL :compdt
IF %start% neq %count% GOTO sortil
IF %swap% neq 0 GOTO sortol
FOR /l %%a IN (1,1,%count%) DO CALL ECHO %%$%%a%%
GOTO :EOF
:set$
SET /a count+=1
SET "$%count%=%~1"
GOTO :eof
:compdt
CALL SET f1=%%$%start%%%
SET /a START +=1
CALL SET f2=%%$%start%%%
FOR /f %%a IN (
'echo f^|xcopy /L /y /d "%sourcedir%\%f1%\world.sav" "%sourcedir%\%f2%\world.sav"'
) DO SET copies=%%a
IF %copies%==0 GOTO :EOF
SET /a swap +=1
SET /a START -=1
SET "$%start%=%f2%"
SET /a START +=1
SET "$%start%=%f1%"
GOTO :eof
This worked for me. You'd need to set sourcedir to suit your purpose.
Essentially, it builds a list of the next-level-down directory names which contain the target filename in variables $1...$whatever, then sorts the names using a simple bubble-sort which relies on the characteristics of xcopy. XCOPY's /L switch simply lists the files that would be copied; /y tells it to 'go ahead (and not copy)' and /d says 'only later files.ECHOingftellsxcopythat the desired "copy" is a file-copy, so it responds1 file(s) copiedor0...` as its last line, depending on whether the source file was later than the destination.
To reverse the order, simply change the if %copies%==0 to if %copies%==1
An idea :
#echo off
Setlocal EnableDelayedExpansion
set $WorkDir="C:\eh\guh\blugh\fneh\mork\workingdir"
for /f "tokens=*" %%a in ('dir /s/b/a-d %$WorkDir%') do (
for /f "tokens=9 delims=\" %%b in ('echo %%a') do (
if /i "%%b"=="world.sav" call:next "%%~pa" %%~ta
)
)
::Resultat
for /f "tokens=2 delims==" %%r in ('set #') do echo %%r
exit/b
:next
for /f "tokens=7 delims=\" %%c in ('echo %~1') do set $Path=%%c
for /f "tokens=1-3 delims=/" %%c in ('echo %~2') do set #%%e%%d%%c=!$path!

Resources