I have the following in a batch file:
:REMOLDFILES
ECHO Removing files older than 14 days. >>%LOGFILE%
cd /d %BKUPDIR%
FOR /f "skip=14 delims=" %%A IN ('DIR /a:-d /b /o:-d /t:c %1*.zip ^2^>nul') DO IF EXIST "%%~fA" ECHO "%%~fA" >>%LOGFILE%
FOR /f "skip=14 delims=" %%A IN ('DIR /a:-d /b /o:-d /t:c %1*.zip ^2^>nul') DO IF EXIST "%%~fA" DEL "%%~fA" >>%LOGFILE%
FOR /f "skip=14 delims=" %%A IN ('DIR /a:-d /b /o:-d /t:c %1*.log ^2^>nul') DO IF EXIST "%%~fA" ECHO "%%~fA" >>%LOGFILE%
FOR /f "skip=14 delims=" %%A IN ('DIR /a:-d /b /o:-d /t:c %1*.log ^2^>nul') DO IF EXIST "%%~fA" DEL "%%~fA" >>%LOGFILE%
IF [%3]==[Y] GOTO SECONDBACKUPDIR
IF [%3]==[y] GOTO SECONDBACKUPDIR
GOTO END
The problem I ran in to is that the backup was not running for a couple of weeks and ended up deleting all of my backups since they were over 2 weeks old.
What I need is for it to keep the last 10 latest backups.
Anyone have an idea how I would do that? I did not write this once since I'm not that familiar with batch files.
You could use FOR /F SKIP to ignore the last 10 most recently modified entries after sorting by last modified date:
for /f "skip=10 eol=: delims=" %%F in ('dir /b /o-d *.zip') do #del "%%F"
You can get a listing of files in reverse order by modified date using the DIR command. Then you just tell your FOR loop to skip the first 10 (note your post code shows 14, but you ask for 10) entries, so whatever is processed is deleted.
REM Update to 14 if needed.
SET Keep=10
FOR /F "usebackq tokens=* skip=%Keep% delims=" %%A IN (`DIR *.zip /B /O:-D /A:-D`) DO DEL "%%A">>%LOGFILE%
Since you are unfamiliar with batch, you can test this command (to see what will be deleted instead of actually deleting it) by replacing DEL with ECHO.
Edit
Since you are also processing log files, why not just delete them in the same loop?
REM Update to 14 if needed.
SET Keep=10
FOR /F "usebackq tokens=* skip=%Keep% delims=" %%A IN (`DIR *.zip /B /O:-D /A:-D`) DO (
ECHO Processing: %%~nA
REM Delete ZIP file.
DEL "%%A"
REM Delete LOG file.
DEL "%%~nA.log"
)>>%LOGFILE%
Related
Can anyone please explain to me how batch scripts work in Windows? I have a folder that contains subfolders, and those contain images. I need a script that automatically deletes images from 7 and up in these subfolders, just to leave a maximum of 6 images in each subfolder, ideally the first 6 alphabetically. I found a few scripts, saved them as .bat, but I have no idea what to do next.
1
#echo off
setlocal
set /a cnt=0
set "keep=6"
for /f "eol=: delims=" %%F in ('dir /b /o-d /a-d *.jpeg') do (
if defined keep (
2>nul set /a "cnt+=1, 1/(keep-cnt)" || set "keep="
) else del "%%F"
)
2
#echo off
for /f "tokens=1* delims=:" %%a in ('dir /b /o-d *.jpeg ^| findstr /N "^"') do (
if %%a gtr 6 del "%%b"
)
3
for /f "skip=7 eol=: delims=" %%F in ('dir /b /o-d /a-d *.jpeg') do #del "%%F"
4
#echo off
setlocal enableextensions disabledelayedexpansion
rem How many elements to keep
set "keep=6"
rem Retrieve folder from batch arguments
set "folder=%~1"
rem If no folder indicated, use current active directory
if not defined folder for %%a in (.) do set "folder=%%~fa"
rem Ensure we are working in the correct folder
pushd "%folder%" && (
rem For each element in the folder, skipping the first n
for /f "skip=%keep% delims=" %%a in (' dir /b /on ') do (
rem If it is a folder, use rmdir, else use del
if exist "%%a\" ( echo rmdir /s /q "%%a" ) else ( echo del "%%a" )
)
rem Work done. Return to previous active directory
popd
) || (
rem Folder change failed
echo Target folder does no exist
)
I finally found a script that works the way I need it to
for /f %%a in ('dir /b /ad') do (
for /f "skip=6" %%b in ('dir /b %%a /on') do (
del %%a\%%b
)
)
I require a batch file that will count folders with a certain name and if there are multiple, the oldest should be deleted. Folders are named:
"01. Daily Backup 20190219",
"01. Daily Backup 20190218" and
"01. Weekly Backup 20190210".
Of these, I only need the "01. Daily Backup 20190218" folder to be deleted.
Counting all folders is fairly easy via:
for /f %%a in ('dir /b /ad %folder%^|find /c /v "" ') do set count=%%a
echo %count%
I am unable to add counting conditions based upon the folder names, for instance "01. Daily*" nor delete the olders. Help is much appreciated.
Here is a scenario using folders that starts with 01. Daily Backup* only, seeing that is the only example you gave.
#echo off
set "folder=01. Daily Backup*"
for /f "delims=" %%i in ('dir /b /ad /o-d "%folder%"') do set "todel=%%i"
for /f %%a in ('dir /b /ad "%folder%" ^| find /c /v ""') do set "count=%%a"
if %count% gtr 1 echo rmdir /S "%todel%"
So we will dir all folders, order by date (newest first) set only the last folder as a variable. then if the counter is more than one, delete the folder which was set as a variable.
Note, this does not perform the actual delete yet, it will simply echo it, to perform the rmdir command, remove echo from the last line.
Edit
Seeing as you want to simply keep the latest folder and delete the rest, simply do this (again, remove #echo from the line to perform the actual task):
#for /f "skip=1 delims=" %%i in ('dir /b /ad /o-d "01. Daily Backup*"') do (
#echo #rmdir /s "%%i"
)
#echo off
REM Location of Reliplan folders and files
set "dir=c:\temp\"
set "name=01. Daily Backup*"
:start
for /f "delims=" %%i in ('dir /b /ad /o-d "%dir%%name%"') do set "todel=%%i"
for /f %%a in ('dir /b /ad "%dir%%name%" ^| find /c /v ""') do set "count=%%a"
if %count% gtr 1 goto del
goto further
:del
rd /s /q "%dir%%todel%"
goto start
:further
if "%name%"=="01. Daily Backup*" (
set "name=01. Weekly Backup*"
goto start
)
if "%name%"=="01. Weekly Backup*" (
goto end
)
:end
In my hard disk I have the following structure:
ROOTFOLDER
├───FOLDER1
│ └───TMPFOLDER
│ ├───FOLDERTODELETE1
│ ├───FOLDERTODELETE2
│ └───FOLDERTODELETE3
├───FOLDER2
│ └───TMPFOLDER
│ ├───FOLDERTODELETE4
│ └───FOLDERTODELETE5
└───FOLDER3
└───TMPFOLDER
├───FOLDERTODELETE6
├───FOLDERTODELETE7
└───FOLDERTODELETE8
I need to create a kind of script (I was thinking about a batch file, but any other solution will be appreciated) to delete all folders within each folders with a specific name (in this case TMPFOLDER) and created before today.
Following to your needs the batch script below will do what you need. Remove the echo in front of the rmdir command if it's okay for you. Take care that the script uses the current working directory. Remove /q if you want to be asked for each directory that should be deleted:
#echo off
set "tmpfolder=TMPFOLDER"
for /f "tokens=*" %%D in ('dir /b /a:d "*"') do (
for /f "tokens=*" %%E in ('dir /b /a:d "%%D\*" ^| findstr /l /x %tmpfolder%') do (
echo Found temp folder: "%%D\%%E"
for /f "tokens=*" %%F in ('dir /b /a:d "%%D\%%E\*"') do (
echo rmdir /s /q "%%D\%%E\%%F"
)
)
)
Edit #1:
The above script does not take care of the creation date of the folder that should be removed. You want only folders to be deleted which have a creation date before today. The following script takes care of that. Look here how to get dates of folder and here how to compare dates:
#echo off
setlocal EnableDelayedExpansion
set "tmpfolder=TMPFOLDER"
for /f "tokens=*" %%D in ('dir /b /a:d "*"') do (
for /f "tokens=*" %%E in ('dir /b /a:d "%%D\*" ^| findstr /x /c:"%tmpfolder%"') do (
rem echo Found temp folder: "%%D\%%E"
for /f "tokens=*" %%F in ('dir /b /a:d "%%D\%%E\*"') do (
rem echo Subfolder: "%%F"
set "curdate=!date!"
set "dirdate="
echo GETDATE
call :getdate dirdate "%%D\%%E\%%F"
set "dirdate=!dirdate:~-4!!dirdate:~3,2!!dirdate:~0,2!"
set "curdate=!curdate:~-4!!curdate:~3,2!!curdate:~0,2!"
rem echo dirdate: "!dirdate!"
rem echo curdate: "!curdate!"
rem echo.
if [!dirdate!] LSS [!curdate!] (
echo rmdir /s /q "%%D\%%E\%%F"
)
)
)
)
goto :EOF
:getdate
rem call: getdate date(dstParam) folder(srcParam)
for /f "skip=5 tokens=1 delims= " %%A in ('dir /a:d /o:d /t:c "%~2"') do (
set "%~1=%%A"
goto :EOF
)
Command reference links from ss64.com:
DelayedExpansion
set
for /f
dir
findstr
if
call
goto
rem
Although an answer has already been accepted, I have decided to post this untested idea as an alternative:
#Echo Off
SetLocal EnableDelayedExpansion
For /F "Delims=" %%A In ('WMIC OS Get LocalDateTime') Do For %%B In (%%~nA
) Do Set "TD=%%B" & Set "TD=!TD:~,8!"
For /D /R "ROOTFOLDER" %%A In ("TMPFOLD?R") Do If /I "%%~nxA"=="TMPFOLDER" (
Set "FP=%%~pA" & Set "FP=!FP:\=\\!"
WMIC FSDir Where "Path='!FP!' And FileName='TMPFOLDER'" Get CreationDate^
|FindStr/B "%TD%">Nul||Echo=RD/S/Q "%%A")
Timeout -1
You may need to change ROOTFOLDER and all instances of TMPFOLDER as necessary, remembering to use a ? to replace one of the characters in the first instance of TMPFOLDER.
If the output appears to be correct, remove the last line and Echo= from the line above it.
Hi guys just got the following code script running to search in a directory for files that contain the string "ABC" and move them to the directory at the end.
for /f "eol=: delims=" %%F in ('dir /b^|find "ABC"') do move /Y "%%F" "C:\DESTINATION_DIRECTORY"
Was wondering how to modify this to not have to be run from the input directory, i.e to add a SOURCE_DIRECTORY variable so I can run this script from elsewhere but have it parse thru the SOURCE_DIRECTORY.
Thanks for any help.
#echo off
set "root=c:\st"
pushd %root% && (
for %%# in ("*ABC*") do echo move /Y "%%~f#" "C:\DESTINATION_DIRECTORY"
)
popd
or
for /f "tokens=* delims=" %%# in ('dir /b "%root%\*ABC*"') do echo move /Y "%root%\%%~nx#" "C:\DESTINATION_DIRECTORY"
for recursive search:
for /f "tokens=* delims=" %%# in ('dir /b /s "%root%\*ABC*"') do echo move /Y "%%~f#" "C:\DESTINATION_DIRECTORY"
I can use this to loop over files:
for %%a in ("%directory%\*.%extension%") do (
echo FILE: %%~fa
)
goto :eof
What if I also rename the files, like this (:rename is a subroutine that renames the files):
for %%a in ("%directory%\*.%extension%") do (
echo FILE: %%~fa
call :rename "%%~fa"
)
goto :eof
In that case, some of the files are renamed (and echoed) two or even three times. I think it's because after they are renamed, in some cases they are regarded as new files that also need to be looped through. However, this does not happen with all the renamed files.
How can I overcome this? I want every file to be renamed only once.
Solution:
:: remove quotes:
:: http://www.dostips.com/?t=Snippets.TrimQuotes
for /f "useback tokens=*" %%a in ('%extension%') do set extension=%%~a
for /f "useback tokens=*" %%a in ('%directory%') do set directory=%%~a
for /f "delims=" %%a in ('dir /b /a-d "%directory%\*.%extension%" ^| sort /r') do (
echo FILE: %directory%\%%a
call :renamingSubroutine "%directory%\%%a"
)
goto :eof
OR:
:: remove quotes:
:: http://www.dostips.com/?t=Snippets.TrimQuotes
for /f "useback tokens=*" %%a in ('%extension%') do set extension=%%~a
for /f "useback tokens=*" %%a in ('%directory%') do set directory=%%~a
for /f "delims=" %%a in ('dir /b /a-d /s /on "%directory%\*.%extension%"') do (
echo FILE: %%~fa
call :renamingSubroutine "%%~fa"
)
goto :eof
try this:
for /f "delims=" %%a in ('dir /b /a-d /s "%directory%\*.%extension%"^|sort /r') do (
echo FILE: %%~fa
call :rename "%%~fa"
)
goto :eof
BTW you shouldn't give batch functions the names of cmd commands (rename).