I'm writing a simple .bat backup script, and as part of it I want the oldest backup (folder) to be deleted upon reaching a set max limit of backups.
Right now I have this:
%COUNTER% is based on the number of backup folders currently in the directory where backups are stored, and is calculated earlier in the script.
%MAXBACKUPS% is just a user-specified number like "10," to say that you only want to keep up to 10 versions of the backups.
:: Delete the oldest backup, but only if we've exceeded the desired number of backups.
IF %COUNTER% gtr %MAXBACKUPS% (
ECHO More than %MAXBACKUPS% backups exist. Deleting oldest...
FOR /f "delims=" %%a in ('dir "..\Backup\*" /t:c /a:d /o:-d /b') do rd /s /q "..\Backup\%%a"
::Increment the counter down since we've just removed a backup folder.
SET /a COUNTER=%COUNTER%-1
)
I would like this script to only delete the one oldest folder in the ..\Backup folder, but as it stands it seems to delete every single folder it finds once it reaches the backup limit, which is obviously not the desired behavior.
You were so close ! :-)
All you need to do is skip the first %MAXBACKUPS% entries when sorted by date descending. You don't even need your COUNTER variable.
:: Preserve only the %MAXBACKUPS% most recent backups.
set "delMsg="
for /f "skip=%MAXBACKUPS% delims=" %%a in (
'dir "..\Backup\*" /t:c /a:d /o:-d /b'
) do (
if not defined delMsg (
set delMsg=1
echo More than %MAXBACKUPS% found - only the %MAXBACKUPS% most recent folders will be preserved.
)
rd /s /q "..\Backup\%%a"
)
A simple way to do this based on your script:
FOR /f "delims=" %%a in ('dir "..\Backup\*" /t:c /a:d /o:-d /b') do set lastfolder=%%a
rd /s /q "..\Backup\%lastfolder%"
So you still loop over each folder, sorted by age, but you overwrite %lastfolder% so at the end it contains only the name of the oldest folder.
Then you delete that folder.
Here's the final block of code I ended up using:
:: Preserve only the %MAXBACKUPS% most recent backups.
FOR /f "skip=%MAXBACKUPS% delims=" %%a in (
'dir "..\Backup\*" /t:c /a:d /o:-d /b'
) do (
ECHO More than %MAXBACKUPS% backups found--Deleting "%%a".
ECHO.
rd /s /q "..\Backup\%%a"
)
It simplifies the deletion message code a bit, and provides the end user with info about what file was deleted in the command prompt window.
Based on dbenham's answer.
FOR /f "delims=" %%a in ('dir "..\Backup\*" /t:c /a:d /o:d /b') do (
rd /s /q "..\Backup\%%a"
goto :break
)
:break
you can break the for loop with goto
Related
So I have a folder called Folder1 and inside of that folder has multiple other Folders for our build. The naming convention of those build folders are the date that they were built. For example: 20190314141438 (which is 2019-03-14 time 14:14:38). So what I like to do is to delete everything except for the last latest 3 folders. I started it out in a batch script but was able to delete it based on last modified date, which works, but need to somehow compare all the folders name and delete the old ones. Here is my script:
if not exist "%Location%" (
echo The Location - "%Location%" does not exist
) ELSE (
for /F "skip=3 delims=" %%i in ('dir "%Location%" /AD /B /O-D 2^>nul') do (
echo Removing "%Location%\%%i"
rd /Q /S "%Location%\%%i"
)
)
I was also thinking if it's not possible with a batch script, I can create a java program that does that if anyone has any idea on how i should start. Thanks.
UPDATE:
Some of the folders will also have a release number at the end of the folder name such as 20190314141438_Release2. How would I tell the batch file to ignore those. I was thinking of using findstr /C:"Release1"and somehow put that in a if else statement?
Thank you LotPings and Mofi for helping me out with this question. I have posted the script that works:
if not exist "%Location%" (
echo The Location - "%Location%" does not exist
) ELSE (
for /F "skip=3 delims=" %%i in ('dir "%Location%" /AD /B /O-N 2^>nul ^|
%SystemRoot%\System32\findstr.exe /I /V /C:Release') do
echo Removing "%Location%\%%i"
rd /Q /S "%Location%\%%i"
)
)
I am trying to delete all but the newest folder using a batch script.
A similar question has already been asked here, so I tried using that as a template and things are getting screwed up.
The folder that I need to purge of all but the newest folder is actually a folder containing backups. In another script, I am backing up the folder that contains this folder, which also includes the folder that this is a backup.
H:\LOS is the folder being backed up.
H:\LOS\DefaultChromeCopy is the folder that contains backups of H:\LOS\Default that are taken everyday.
I want to backup H:\LOS, but I don't need any of the folders in DefaultChromeCopy since I'm already backing up Default. I will be running this weekly, so I want to temporarily move the newest folder in the DefaultChromeCopy directory to T:\Backups for safe keeping, then delete all the folders in DefaultChromeCopy, and then backup H:\LOS. That backup will also go to T:\Backups, and then I can move the folder that was the newest folder in DefaultChromeCopy back to its original location.
So in the end, I will have a backup of H:\LOS with an empty DefaultChromeCopy folder, and all the folders in H:\LOS\DefaultChromeCopy will have been deleted except for the newest one (which was "moved" temporarily).
So, using the code from the other SO answer as a starting put, I have this (without the asterisks around the echo):
if not exist "T:\Backups" md "T:\Backups"
set "workdir=H:\LOS\DefaultChromeCopy"
set "folder="
for /f "tokens=* delims=" %%i in ('dir %workdir% /AD /B /TW /O-D') do (
set "folder=%%~fi"
**echo** robocopy H:\LOS\DefaultChromeCopy\%folder% T:\Backups\%folder% /e /w:0 /r:2
goto :break
)
:break
echo newest... %folder%
for /f "skip=1 tokens=* delims=" %%i in ('dir %workdir% /AD /B /TW /O-D') do (
echo rd /s /q "%%~fi"
)
I've set up a dummy drive H and dummy drive T and modeled the folders in order to test this out.
You can see that ne is the newest folder.
With the echo denoted by asterisks, I get:
newest... H:\ne
rd /s /q "H:\sdf"
rd /s /q "H:\6"
rd /s /q "H:\5"
rd /s /q "H:\4"
rd /s /q "H:\3"
rd /s /q "H:\2"
rd /s /q "H:\1"
The path for "newest" used to be right but now even that is not right.
I've stopped here, because so much is going wrong already. How can I fix the paths? Also, if I run without the echo, ALL the folders in DefaultChromeCopy (or sometimes, even stranger, all of them except ne and sdf) get copied to T:\Backups, which is not what is supposed to happen. Only the newest folder is supposed to get copied.
Here is the part that will actually do the "backup", and then move %folder% back where it came from (%folder% is the newest folder from DefaultChromeCopy).
robocopy "H:\LOS\" "T:\Backups\LOS_Backup_%DATE:~-4%-%DATE:~4,2%-%DATE:~7,2%_%TIME:~0,2%.%TIME:~3,2%" /e /w:0 /r:2
robocopy T:\Backups\%folder% H:\LOS\DefaultChromeCopy /e /w:0 /r:2
start "" "T:\Backups"
The directories in DefaultChromeCopy are not modified after they are created, so Date Created and Date Modified should be the same. I only want to keep the newest folder in DefaultChromeCopy, by moving it to T:\Backups so I can delete all the folders in DefaultChromeCopy for the backup (I don't need even the newest backup in the big backup I'm taking). Hope this all makes sense...
UPDATE:
Running:
setlocal ENABLEDELAYEDEXPANSION
set "workdir=H:\LOS\DefaultChromeCopy"
set "folder="
for /f "tokens=* delims=" %%i in ('dir %workdir% /AD /B /TW /O-D') do (
set "folder=%%~fi"
echo %%~fi
echo robocopy %%~fi T:\Backups\!folder! /e /w:0 /r:2
goto :break
)
:break
echo newest... !folder!
for /f "skip=1 tokens=* delims=" %%i in ('dir %workdir% /AD /B /TW /O-D') do (
echo rd /s /q "%workdir%\%%~i"
)
produces:
H:\ne
robocopy H:\ne T:\Backups\H:\ne /e /w:0 /r:2
newest... H:\ne
rd /s /q "H:\LOS\DefaultChromeCopy\sdf"
rd /s /q "H:\LOS\DefaultChromeCopy\6"
rd /s /q "H:\LOS\DefaultChromeCopy\5"
rd /s /q "H:\LOS\DefaultChromeCopy\4"
rd /s /q "H:\LOS\DefaultChromeCopy\3"
rd /s /q "H:\LOS\DefaultChromeCopy\2"
rd /s /q "H:\LOS\DefaultChromeCopy\1"
So it looks like the directories that are supposed to be deleted are getting deleted, but the "newest" part is still a little wonky. I need to figure out how to get "H:\LOS\DefaultChromeCopy\ne". Right now:
%%~fi --> H:\ne
%workdir%\%%~fi --> H:\LOS\DefaultChromeCopy\H:\ne
T:\Backups\!folder! --> T:\Backups\H:\ne
T:\Backups\%folder% --> T:\Backups\
?????????????!!!!! --> H:\LOS\Default\ChromeCopy\ne & T:\Backups\ne
Fortunately, I found a sort of a workaround. There should only be 1 folder left in DefaultChromeCopy, so even though I can't figure out how to reference it, I can reference its parent. Thus, running the following deletes all but the newest folder from DefaultChromeCopy, backs DefaultChromeCopy up to T:\Backups, deletes everything in DefaultChromeCopy, backs up H:\LOS to T:\Backups, then copies DefaultChromeCopy back to H:\LOS\DefaultChromeCopy and deletes it from T:\Backups.
Here is the final working script. Thanks for everyone's help:
#echo off
echo Beginning LOS backup - deleting all Chrome backups except the newest one
if not exist "T:\Backups" md "T:\Backups"
setlocal ENABLEDELAYEDEXPANSION
set "chromebackups=H:\LOS\DefaultChromeCopy"
set "folder="
for /f "tokens=* delims=" %%i in ('dir %chromebackups% /AD /B /TW /O-D') do (
set "folder=%%~fi"
echo folder is !folder!
goto :deleteolds
)
:deleteolds
for /f "skip=1 tokens=* delims=" %%i in ('dir %chromebackups% /AD /B /TW /O-D') do (
rd /s /q "%chromebackups%\%%~i"
)
robocopy "H:\LOS\DefaultChromeCopy" "T:\Backups\DefaultChromeCopy" /e /w:0 /r:2
set topurge="H:\LOS\DefaultChromeCopy"
cd /d %topurge%
for /f "delims=" %%i in ('dir /b') do (rmdir "%%i" /s/q || del "%%i" /s/q)
setlocal DISABLEDELAYEDEXPANSION
robocopy "H:\LOS" "T:\Backups\LOS_Backup_%DATE:~-4%-%DATE:~4,2%-%DATE:~7,2%_%TIME:~0,2%.%TIME:~3,2%" /e /w:0 /r:2
robocopy "T:\Backups\DefaultChromeCopy" "H:\LOS\DefaultChromeCopy" /e /w:0 /r:2
rmdir "T:\Backups\DefaultChromeCopy" /s /q
start "" "T:\Backups"
echo LOS Backup has completed! You can now ZIP the folder in T:\Backups\, upload that to the LOS Repository server, and then delete T:\Backups manually.
I am looking to change the last modified time stamp of all my files and directories in "My documents". The reason is that all documents older than 3 months get deleted on the server I am using. This is just a trick to keep my documents as I often need them again after a longer period of time.
What I managed so far with the code below is to change the time stamp "last modified" of all files, including in the subdirectories. But it doesn't change the time stamp of the subdirectories themselves.
#echo off
for /f "delims=" %%a in ('dir /ad /b /s') do (
pushd "%%a"
copy /B /Y *.*+,,
popd
)
I got this piece of code after some research, but do not understand it fully...
I hope you guys can help
I have solved it with the following code.
As #aschipfl suggested, I created a random file and then immediately deleted it afterwards
#echo off
copy /B /Y *.*+,, >nul
echo. > randomfile.txt
if exist randomfile.txt del randomfile.txt /Q
for /f "delims=" %%a in ('dir /ad /b /s') do (
pushd "%%a"
copy /B /Y *.*+,, >nul
echo. > randomfile.txt
if exist randomfile.txt del randomfile.txt /Q
popd
)
cls
echo All files and folders updated %date% %time%
pause
I have a question regarding deleting the oldest file after a folder gets an X amount of files with the same extension, in this case, all the files share in common the extension *.bak, they are small files that I create for my firefox RES, they have imprinted on the title, the date and hour of creation, and that's as far as I can go.
Anyways, I've stumbled across this: Batch Script to delete oldest folder in a given folder. And I'm struggling to get it to work on my idea.
The thing is that I want the batch to simply check which file is the oldest after it creates a new one using this simple line of code.
copy /y store.json "%DROPBOX%\RES BACKUPS\store.json %date:~-4,4%-%date:~-7,2%-%date:~-10,2%_%time:~0,2%hs-%time:~3,2%min-%time:~6,2%s.bak"
You can use this:
#echo off
for /f "delims=" %%a in ('dir /b /a-d /t:w /o:d "%DROPBOX%\RES BACKUPS\*.bak"') do (
del "%%a"
goto :breakLoop
)
:breakLoop
I suggest first testing it with echo del "%%a" to make sure it deletes the right file.
This works by getting the output of the dir command, which shows all files in bare format (only filenames, not sizes etc.) sorted by oldest files first. It then deletes the first file found, and breaks the loop.
A version that keeps deleting files while there are more than a specific amount:
#echo off
set "source=%DROPBOX%\RES BACKUPS\*.bak"
set "minFiles=5"
for /f %%A in ('dir "%source%" /a-d-s-h /b ^| find /v /c ""') do if %%A leq %minFiles% goto :eof
:loop
for /f "delims=" %%a in ('dir /b /a-d /t:w /o:d "%source%"') do (
del "%%a"
goto :breakLoop
)
:breakLoop
for /f %%A in ('dir "%source%" /a-d-s-h /b ^| find /v /c ""') do if %%A gtr %minFiles% goto :loop
pause
You can make this non-looping (but still only delete if there are more than 5) by removing the line for /f %%A in ('dir "%source%" /a-d-s-h /b ^| find /v /c ""') do if %%A gtr %minFiles% goto :loop
I have a directory that has a 10 sub-directories. Each of these holds different .bak files. I'm trying to create a script that will check to see if X number of files are there and if the number of files exceeds X, it deletes the oldest file. In other words, I want 20 iterations of a .bak file. When the 21st one shows up, I want the batch file to delete the oldest one.
Is this possible?
If so, can I create a single script that looks in all the sub-directories?
Thanks in advance.
Two options included. The first one will leave %maxFiles% bak files under each of the folders. The second one (windows Vista or later OS is required as robocopy is used to obtain the sorted list of files) will leave %maxFiles% in total
#echo off
setlocal enableextensions disabledelayedexpansion
set "rootFolder=%cd%"
set "maxFiles=20"
rem Option 1 - Keep %maxFiles% inside each of the subfolders
for /d /r "%rootFolder%" %%z in (*) do for /f "skip=%maxFiles% delims=" %%a in (
'dir /tc /o-d /a-d /b "%%~fz\*.bak" 2^>nul'
) do echo del "%%~fz\%%~nxa"
echo ------------------------------
rem Option 2 - Keep %maxFiles% in total under all the subfolders
for /f "skip=%maxFiles% tokens=2,*" %%a in ('
robocopy "%rootFolder%" "%rootFolder%" *.bak /l /nocopy /is /s /njh /njs /ndl /nc /ns /ts
^| findstr /v /r /e /i /c:"%rootFolder:\=\\%\\[^\\]*"
^| sort /r
') do echo del "%%b"
del commands are only echoed to console. If the output is correct, remove the echo command to remove the files
assumes that you want to check the number of files from the parent directory.Can be done also for each sub-directory.
#echo off
setlocal
set "max_number_files=20"
set "parrent_dir=c:\whatever_you_need"
set "extension=.bak"
pushd "%parrent_dir%"
set "count=0"
setlocal enableDelayedExpansion
for /f "delims=" %%a in ('dir /s /b /a:-d /o:-d /t:c *%extension%') do (
set /a count=count+1
if 1!count! GTR 1!max_number_files! (
rem --- remove the echo to activate deletion
echo del /q /f "%%~a"
)
)
popd
endlocal
endlocal
This will check each folder under d:\base\folder and if there are more than 20 *.bak files it will remove the oldest ones so only 20 *.bak file remain, in each folder.
Test it on some sample folders.
#echo off
for /d /r "d:\base\folder" %%a in (*) do (
pushd "%%a"
for /f "skip=20 delims=" %%b in ('dir /b /a-d /o:-d *.bak ') do del "%%b"
popd
)