16

How do I create a batch file to delete files older than a specified date?

This does not seem to work;

:: --------DELOLD.BAT----------
@echo off
SET OLDERTHAN=%1
IF NOT DEFINED OLDERTHAN GOTO SYNTAX

for /f "tokens=2" %%i in ('date /t') do set thedate=%%i
type %1
pause
set mm=%thedate:~0,2%
set dd=%thedate:~3,2%
set yyyy=%thedate:~6,4%

set /A dd=%dd% - %OLDERTHAN%
set /A mm=%mm% + 0

if /I %dd% GTR 0 goto DONE
set /A mm=%mm% - 1
if /I %mm% GTR 0 goto ADJUSTDAY
set /A mm=12
set /A yyyy=%yyyy% - 1

:ADJUSTDAY
if %mm%==1 goto SET31
if %mm%==2 goto LEAPCHK
if %mm%==3 goto SET31
if %mm%==4 goto SET30
if %mm%==5 goto SET31
if %mm%==6 goto SET30
if %mm%==7 goto SET31
if %mm%==8 goto SET31
if %mm%==9 goto SET30
if %mm%==10 goto SET31
if %mm%==11 goto SET30
if %mm%==12 goto SET31

goto ERROR

:SET31
set /A dd=31 + %dd%
goto DONE

:SET30
set /A dd=30 + %dd%
goto DONE

:LEAPCHK
set /A tt=%yyyy% %% 4
if not %tt%==0 goto SET28
set /A tt=%yyyy% %% 100
if not %tt%==0 goto SET29
set /A tt=%yyyy% %% 400
if %tt%==0 goto SET29

:SET28
set /A dd=28 + %dd%
goto DONE

:SET29
set /A dd=29 + %dd%

:DONE
if /i %dd% LSS 10 set dd=0%dd%
if /I %mm% LSS 10 set mm=0%mm%
for %%i in (*.*) do (
set FileName=%%i
call :PROCESSFILE %%~ti
)

set mm=
set yyyy=
set dd=
set thedate=
goto EXIT

:SYNTAX
ECHO.
ECHO USAGE:
ECHO DELOLD X
ECHO   Where X is the number of days previous to Today.
ECHO.
ECHO EX: "DELOLD 5" Deletes files older than 5 days.
GOTO EXIT

:PROCESSFILE
set temp=%1
set fyyyy=20%temp:~6%
set fmm=%temp:~0,2%
set fdd=%temp:~3,2%
if /I %fyyyy% GTR 2069 set fyyyy=19%temp:~6%


:: ***************************************
:: * This is where the files are deleted *
:: * Change the ECHO command to DEL to   *
:: * delete. ECHO is used for test.      *
:: ***************************************
if /I %yyyy%/%mm%/%dd% GEQ %fyyyy%/%fmm%/%fdd% (
ECHO %FileName%
)

set temp=
set fyyyy=
set fmm=
set fdd=

:EXIT

:: ----------END-DELOLD.BAT-------------
double-beep
  • 5,031
  • 17
  • 33
  • 41
  • A new method based in a .BAT file that use internal CMD.EXE commands only has been posted here: http://stackoverflow.com/questions/9746778/ms-dos-batch-delete-old-files-in-directory/9747065#9747065 – Aacini Mar 17 '12 at 04:10
  • I don't agree this is a duplicate question... it is similar but not the same: removing files older than a given date vs files older than N days, to use the second in implies computing the amount of days between two dates, which is not trivial in a batch file – cbuchart May 15 '19 at 10:02

8 Answers8

10

If you're on a Windows Server and/or have the Server Resource Kit installed, forfiles may be exactly what you're looking for.

Examples: print all file names, older than 180 days

forfiles /S /D -180 /C "cmd /C Echo @Path" >olderthan180days.txt

delete all PDF files, older than 365 days

forfiles /S /M *.pdf /D -365 /C "cmd /C Del @Path"
ilshat
  • 23
  • 5
ℳ  .
  • 361
  • 2
  • 10
10

I use this script:

////////////////////////////////////////////////////////
// Deletes file older than a number of days 
// in the current directory
////////////////////////////////////////////////////////
// Usage: wscript DeleteOlderThan.js [#Days]
// By default, remove files older than 30 days
////////////////////////////////////////////////////////

function removeDays(date, nDays)
{
    var dateRet = date
    return dateRet.setDate(date.getDate() - nDays);
}

function addSlash(strPath)
{
    var c = strPath.substr(-1, 1);
    if( c !== '\\' && c !== '/' )
    {
        strPath += '\\';
    }
    return strPath;
}

// Read arguments
var nDays = WScript.Arguments(0) || 30;

// Create system objects
var fs = WScript.CreateObject("Scripting.FileSystemObject");
var shell = WScript.CreateObject("WScript.Shell");

// Retrieve current directory
var strDirectoryPath = addSlash(shell.CurrentDirectory);

// Compute date
var dateNow = new Date();
var dateTest = removeDays(dateNow, nDays);

// Iterate on files
var folder = fs.GetFolder(strDirectoryPath);
var files = folder.Files;

for( var it = new Enumerator(files); !it.atEnd(); it.moveNext() )
{
    var file = it.item();

    if( file.DateLastModified < dateTest)
    {
        file.Delete(true);
    }
}

which I invoke every day with:

wscript "C:\Program Files\Utils\DeletesOlderThan.js" 30
Vincent Robert
  • 35,564
  • 14
  • 82
  • 119
7

eJames: I found your xcopy solution to work very well, indeed! The thing I like most about it is that it should work in Windows language versions other than English as well, since the format of the XCOPY parameters seems to be date-setting independent. Wonderful! ;]

One improvement would be to pre-create the FILES_TO_KEEP.TXT file so that if no file match the keep criteria, the second XCOPY statement can still go ahead and do the delete (it fails if it cannot find the FILES_TO_KEEP.TXT file). Here's my script (please note in this example I changed it to only delete *.pdf files and I also changed the temp file name to make more sure there are no potential conflicts, as well as cleaning up the temp file afterwards):

@echo off
SET OLDERTHAN=%1
IF NOT DEFINED OLDERTHAN GOTO SYNTAX

echo >> ~~~FILES_TO_KEEP.TXT~
for /f "tokens=*" %%a IN ('xcopy *.pdf /d:%1 /L /I null') do if exist %%~nxa echo %%~nxa >> ~~~FILES_TO_KEEP.TXT~
for /f "tokens=*" %%a IN ('xcopy *.pdf /L /I /EXCLUDE:~~~FILES_TO_KEEP.TXT~ null') do if exist "%%~nxa" del "%%~nxa"
del ~~~FILES_TO_KEEP.TXT~

GOTO END

:SYNTAX
ECHO.
ECHO USAGE:
ECHO DELOLD mm-dd-yyyy
ECHO   Where mm-dd-yyyy is the date prior to which you want to delete files.
ECHO.
ECHO EX: "DELOLD 10-17-2008" Deletes files older than October 17, 2008.
ECHO.
ECHO This should work on any language version of Windows, but has only been 
ECHO tested in English-US versions.
GOTO END

:END
HerbCSO
  • 762
  • 1
  • 8
  • 20
7

Edit: I figured it out.

To delete all files older than a given date:

REM del_old.bat
REM usage: del_old MM-DD-YYY
for /f "tokens=*" %%a IN ('xcopy *.* /d:%1 /L /I null') do if exist %%~nxa echo %%~nxa >> FILES_TO_KEEP.TXT
for /f "tokens=*" %%a IN ('xcopy *.* /L /I /EXCLUDE:FILES_TO_KEEP.TXT null') do if exist "%%~nxa" del "%%~nxa"

To delete all files newer than a given date:

REM del_new.bat
REM usage: del_new MM-DD-YYYY
for /f "tokens=*" %%a IN ('xcopy *.* /d:%1 /L /I null') do if exist "%%~nxa" del "%%~nxa"
e.James
  • 116,942
  • 41
  • 177
  • 214
1

My solution works if you

  • either have a touch utility on your system (which I do)
  • or can afford to temporarily change system date using date command (which is probably not the case, but who knows)

Here's the idea:

  1. In the target directory, create a signal file (with a unique name), and with timestamp equal to your deletion threshold time. It can be done with touch (which accepts desired timestamp as a parameter), or by remembering current date with date /T, changing system date to desired with date <param>, and restoring the original date.

  2. Use for /f %%I in ('dir /od') to iterate over all files ordered by date, deleting them one by one. After you encounter (and delete) the signal file, stop deleting.

atzz
  • 17,507
  • 3
  • 35
  • 35
  • 1
    This seems like an incredibly risky approach compared to the other answers here. – Dan Bechard Mar 25 '14 at 18:28
  • @Dan If you are referring to the possibility that something will mess with the signal file, it can be guarded against by splitting (2) into two stages: **2.1** build the script by running the loop as above, echoing the del command with file name into a temp file; **2.2** call said temp file, but only if you encountered your signal file. Otherwise, abort. Anyway, this solution is a kludge, of course. – atzz Mar 26 '14 at 21:06
  • 1
    I was just thinking if you accidentally ordered the files incorrectly you might delete thousands of files before reaching the signal file that you didn't want to delete. I don't like the idea of having a signal file vs. explicitly checking the time stamp of every file before it's deleted to be 100% certain you are okay with losing it. I also don't quite understand how your approach deals with subdirectories (not sure if that was a requirement for OP, but it is for me). – Dan Bechard Mar 26 '14 at 21:30
  • 1
    @Dan IMO, ordering the files incorrectly is no greater danger than mistyping the cutoff date, with same result. Subdirectories can be handled by applying the whole procedure recursively. ..Though I'm not sure why I'm trying to keep this approach viable in an expanding set of requirements. If doing this on a PC under my control, I'd just grab a Win port of GNU `find` (e.g. from UnxUtils) and be done with it. :) – atzz Mar 26 '14 at 22:17
  • Thanks for the tip, I have Git Bash installed which comes with GNU `find`. ;) – Dan Bechard Mar 27 '14 at 12:42
1

Perhaps you would like this: http://blog.jumlin.com/2010/10/move-files-in-folders-and-subfolders-older-than-one-year/

Thats a script that will move files older than one year, it even supports various date formats and subfolders. You could make a few changes to make it delete instead of move them. Its a very complete script with comments and explanations.

0

I wonder why you have to use the ole DOS shell... Python or Windows Powershell would be the right choices in 2008 :)

friol
  • 6,996
  • 4
  • 44
  • 81
  • He's using set /a. No way that would work in DOS. So he uses cmd, actually which is still a very sane choice (even if cumbersome), since it's the only thing that works on every Windows (except WSH, but that can be locked down with group policies). – Joey Mar 09 '09 at 14:35
-1

I don't know if you can do that with .BAT files and what few tools Windows comes with, but you sure can with .js (JScript) or .vbs (VBScript) files. You are doing this under Windows, right? If so, then Windows can process .js and .vbs files just as well as .bat files by default. They are far more powerful.

And, if you happen to be targeting only Windows Server 2008, there's PowerShell which is even better (downloadable for other Windows versions).

Vilx-
  • 104,512
  • 87
  • 279
  • 422