Batch file that keeps the 7 latest files in a folder - file

Can anyone help me create a batch file? Basically, my goal is to create a batch file that will keep the LATEST 7 .txt files (in other words, the newest) in the folder and subsequently delete the rest. That's IF there are more than 7 files in the folder.
The problem I'm having right now is the fact that the batch file that I have created deletes most of the files because their date is from a month or two or so. I want to keep the latest 7 files at all times no matter how old they are.
So this is what I have -
#echo off
setlocal enableextensions
rem ********************************************************************************
rem ******************************* LOCAL VARIABLES ******************************
rem ********************************************************************************
SET TargetDirectory="C:\TEMP\test"
SET No_of_fles_to_keep=7
SET count=0
set cnt=0
rem ********************************************************************************
cd /d %TargetDirectory%
REM timeout /T 500
for %%x in (*) do set /a count+=1
for %%A in (*.bat) do set /a cnt+=1
cd /d %TargetDirectory%
REM timeout /T 500
IF %count% gtr %No_of_fles_to_keep% forfiles -p %TargetDirectory% -s -m "*.txt" -d -%No_of_fles_to_keep% -c "cmd /c del #path"
echo %count%
echo File count = %cnt%
Any help is appreciated.

You can use DIR with /O-D to list the text files in descending timestamp order. FOR /F allows you to iterate over each file. SET /A is used to keep track of how many files have been listed so far. Now comes the tricky part.
Within a code block you normally need to use delayed expansion to work with the value of a variable that was set earlier in the same block. But delayed expansion can cause problems in a FOR loop if the FOR variable value contains !, and ! is valid in file names. I get around the problem by using SET /A to intentionally divide by 0 when the 7th file name has been read. This raises an error that causes the conditional code to execute that undefines the KEEP variable. From that point on, all remaining files are deleted.
#echo off
setlocal
set /a cnt=0
set "keep=7"
for /f "eol=: delims=" %%F in ('dir /b /o-d /a-d *.txt') do (
if defined keep (
2>nul set /a "cnt+=1, 1/(keep-cnt)" || set "keep="
) else del "%%F"
)
Update
Oh my goodness, I just realized there is a trivial solution. Just use the FOR /F SKIP option to ignore the first 7 entries after sorting by last modified date, descending.
for /f "skip=7 eol=: delims=" %%F in ('dir /b /o-d /a-d *.txt') do #del "%%F"
You don't even need a batch file. Just change %% to % if run from the command prompt.

The Batch file below use a simpler approach. It use findstr /N "^" command to number each file, then it just compare each number to keep first seven files and delete the rest...
#echo off
for /f "tokens=1* delims=:" %%a in ('dir /b /o-d *.txt ^| findstr /N "^"') do (
if %%a gtr 7 del "%%b"
)
Antonio

If you don't write DOS scripts frequently which I don't, here is a summation of what others noted.
Other examples here will need the batch file in the same folder that you're deleting from.
To delete from another path: (Notice you have to add the path twice to the search and to the delete)
SET targetDir="C:\Test\Files\"
for /f "skip=7 eol=: delims=" %%F in ('dir /b /o-d /a-d %targetDir%*.txt') do #del "%targetDir%""%%F"
Thanks #dbenham, #SmileyFace, #user2924127 and all others who helped bring the answers.

This will keep 7 latest .txt files and remove all other .txt files
Execute below command in same directory from which you want to delete files
On command prompt
for /f "skip=7 eol=: delims=" %F in ('dir /b /o-d /a-d *.txt') do #del "%F"
Inside batch script
for /f "skip=7 eol=: delims=" %%F in ('dir /b /o-d /a-d *.txt') do #del "%%F"

Related

BAT batch file to count files in a folder and then subtract 1

I have a BAT script that counts the number of files in a folder and exports the results into a .txt. It works great, but I'm in a situation where I need to subtract 1 from the value it's currently counting. How could I alter my script to do that?
#echo off
FOR /D %%G in ("*") DO (
PUSHD "%%G"
FOR /F "delims=" %%H in ('dir /a-d /b * ^|find /C /V ""') DO echo %%G %%H>>"..\count.txt"
POPD
)
Your goal is to use %%H with the SET /A command to do the Arithmetic. I chose to use %%G as part of the DIR command. This way you do not need PUSHD and POPD. I also chose to use an IF command to make sure the count is not zero so that it does not substract 1.
I moved the redirection of the output at the end because this opens the file for writing once instead of every time it writes a directory to the output.
The CALL command and the double percent symbols on the variable allows us to use the variable without having to enable delayed expansion.
#echo off
(FOR /D %%G in ("*") DO (
FOR /F "delims=" %%H in ('dir /a-d /b "%%G\*" 2^>NUL ^|find /C /V ""') DO (
IF NOT "%%H"=="0" SET /A "count=%%H-1"
CALL echo %%G %%count%%
)
))>count.txt

Batch file to append several text documents to one document

I have created a batch file which should do several things, including appending all text documents of a certain format into one text file provided there are more than one text files of this format in the directory. This section of the code is below:
:multiple
SET /a count=0
ECHO.> "%location%\UAV_camera_coords_all.txt"
FOR /r "%location%\Output" %%G in ("UAV_camera_coords_*.txt") do set /a count+=1
IF %count% GTR 1 (
FOR /r "%location%\Output" %%G in ("*.txt") DO (
SET file=%%~G
TYPE "%file%">>"%location%\UAV_camera_coords_all"
)
GOTO :end
It seems that the code is crashing upon reaching the if statement even though the count variable is greater than one. None of the code in the if statement is executed and indeed none of the code which should come after the if statement is executed either. Is there any syntax or other error which may be causing this?
Besides my comment. I assume that you are not really planning on typing the output of *.txt but instead only UAV_camera_coords_*.txt.. if not, feel free to change it back to *.txt
#echo off
for /f "tokens=1,*" %%i in ('dir /s "%location%\UAV_camera_coords_*.txt" ^| findstr "File(s)"') do set cnt=%%i
if %cnt% gtr 1 (
for /f %%a in ('dir /b /s "%location%\UAV_camera_coords_*.txt"') do type "%%~a"
)>"%location%\UAV_camera_coords-all.txt"
Note, I changed the output filename to be -all and not _all as that would type the file onto itself if it was to be a txt file as well.
Edit adding back original answer, before I realised you were recursively searching through directories:
#echo off
for /f "tokens=1,*" %%i in ('dir "UAV_camera_coords_*.txt" ^| findstr "File(s)"') do if %%i gtr 1 type "UAV_camera_coords_*.txt">>"%location%\UAV_camera_coords_all"
Just for the purpose of providing an alternative, this one uses xcopy to check the file count, and copy to merge them.
PushD "%location%\Output" 2>NUL && For /F %%G In ('""%__AppDir__%xcopy.exe" "UAV_camera_coords_*.txt" . /SQL"')Do If %%G Gtr 1 Copy /Y /B "UAV_camera_coords_*.txt" "..\UAV_camera_coords_all.txt">NUL & PopD

batch with a lot of for loops

So i made this batch to psarc extract all *.pak files, which will always give *.mbin files that often have the same name. it's then supposed to look for all extracted subfolders and then look for the last created *.mbin file from all of the subfolders and rename it to its current name plus a number. but i get very weird results.
setlocal ENABLEDELAYEDEXPANSION
set number=0
cd /d "C:\Users\storm\Desktop\No Man's Sky\GAMEDATA\PCBANKS\MODS"
for /r %%f in (*.pak=) do (
psarcMBIN.exe extract %%~nxf
set /A number=!number!+1
FOR /F "tokens=" %%a in ('dir /a:d /s') do (
cd /d "%%a"
FOR /F "tokens=" %%G in ('dir /b /a:-d /o:d "*.mbin"') do set newest=%%G
rename "!newest!" "!newest!!number!.mbin"
)
)
pause
The result basically is just:
1. psarc extracted
2. psarc tried to extract next file but cannot overwrite
The other parts of the main for loop are not even shown

BATCH Delete oldest backup file when creating a new one

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

Batch script for loop, variable not incrementing, need to copy/rename duplicate files

Im trying to copy css files from IE's cache folder to some folder in C:
The thing is theres lots of duplicates but I want to keep them all, so I made a batch script to copy all css files and add a counter/index variable to the beginning of each file. The problem is the variable is not incrementing and I dont know why? This is my script:
#echo off
setlocal ENABLEDELAYEDEXPANSION
set /a c=0
for /f "tokens=*" %%A in ('dir /b /s /a-d "C:\Users\%username%\AppData\Local\Microsoft\Windows\Temporary Internet Files\Content.IE5\*.css"') do (
set /a c=c+1
copy "%%A" "C:\Target\%c%_%%~nxA"
)
endlocal
Instead of some 30 css files being copied (I know this cuz I can see them in IE's cache folder) Im getting only about 10 copied and they just have "0_" appended at the front instead of an incrementing number (1-infinity).
I also tried !c! instead of %c% in the copy line part but it just adds literally "!c!" instead of the variables' value.
What am I doing wrong here?
Not as fast (one dir per file copy), but get independent numeration for each css file
set source=C:\Users\%username%\AppData\Local\Microsoft\Windows\Temporary Internet Files\Content.IE5
for /f "tokens=*" %%A in ('dir /b /s /a-d "%source%\*.css"') do (
for /f %%C in ('dir /b "c:\target\*_%%~nxA" ^| find /c "_"') do (
copy "%%A" "c:\target\%%C_%%~nxA"
)
)
You did set enabledelayedexpansion but you are not using it in your loop. You should give this a try, this is what worked for me:
#echo off
setlocal ENABLEDELAYEDEXPANSION
set /a c=0
for /f "tokens=*" %%A in ('dir /b /s /a-d "C:\Users\%username%\AppData\Local\Microsoft\Windows\Temporary Internet Files\Content.IE5\*.css"') do (
set /a c=c+1
copy "%%A" "C:\Target\!c!_%%~nxA"
)
endlocal
The only difference is line 6 where I changed %c% to !c!.

Resources