我正在寻找一种方法来删除批处理文件中超过7天的所有文件。我在网上搜索了一下,找到了一些包含数百行代码的示例,还有一些示例需要安装额外的命令行实用程序来完成任务。

在BASH中,只需几行代码就可以完成类似的工作。在Windows中,似乎可以为批处理文件做一些简单的事情。我正在寻找一个解决方案,工作在标准的Windows命令提示符,没有任何额外的实用程序。请不要使用PowerShell或Cygwin。


享受:

forfiles -p "C:\what\ever" -s -m *.* -d <number of days> -c "cmd /c del @path"

更多细节请参见forfiles文档。

要了解更多信息,请参考Windows XP命令行的A-Z索引。

如果您的计算机上没有安装forfiles,请将其从任何Windows Server 2003复制到您的Windows XP计算机的%WinDir%\system32\。这是可能的,因为EXE在Windows Server 2003和Windows XP之间完全兼容。

后续版本的Windows和Windows Server默认安装了它。

Windows 7及更新版本(包括Windows 10):

语法略有变化。因此更新后的命令为:

forfiles /p "C:\what\ever" /s /m *.* /D -<number of days> /C "cmd /c del @path"

你也许能搞定这件事。你可以看一下这个问题,一个更简单的例子。当你开始比较日期时,复杂性就来了。判断日期是否较大可能很容易,但如果需要实际获得两个日期之间的差异,则需要考虑许多情况。

换句话说,不要试图发明这个,除非你真的不能使用第三方工具。


Ok有点无聊,想出了这个,它包含了我的版本,一个穷人的Linux纪元替代品,仅限于日常使用(没有时间保留):

7 daysclean.cmd

@echo off
setlocal ENABLEDELAYEDEXPANSION
set day=86400
set /a year=day*365
set /a strip=day*7
set dSource=C:\temp

call :epoch %date%
set /a slice=epoch-strip

for /f "delims=" %%f in ('dir /a-d-h-s /b /s %dSource%') do (
    call :epoch %%~tf
    if !epoch! LEQ %slice% (echo DELETE %%f ^(%%~tf^)) ELSE echo keep %%f ^(%%~tf^)
)
exit /b 0

rem Args[1]: Year-Month-Day
:epoch
    setlocal ENABLEDELAYEDEXPANSION
    for /f "tokens=1,2,3 delims=-" %%d in ('echo %1') do set Years=%%d& set Months=%%e& set Days=%%f
    if "!Months:~0,1!"=="0" set Months=!Months:~1,1!
    if "!Days:~0,1!"=="0" set Days=!Days:~1,1!
    set /a Days=Days*day
    set /a _months=0
    set i=1&& for %%m in (31 28 31 30 31 30 31 31 30 31 30 31) do if !i! LSS !Months! (set /a _months=!_months! + %%m*day&& set /a i+=1)
    set /a Months=!_months!
    set /a Years=(Years-1970)*year
    set /a Epoch=Years+Months+Days
    endlocal& set Epoch=%Epoch%
    exit /b 0

使用

set /a strip=day*7:将保留的天数改为7。

set dSource=C:\temp:这是检查文件的起始目录。

笔记

这是非破坏性代码,它将显示将要发生的事情。

变化:

if !epoch! LEQ %slice% (echo DELETE %%f ^(%%~tf^)) ELSE echo keep %%f ^(%%~tf^)

像这样:

if !epoch! LEQ %slice% del /f %%f

所以文件会被删除

2月:硬编码为28天。六分之二的年龄是一个地狱,真的。如果有人有一个不需要添加10行代码的想法,请继续发表,这样我就可以把它添加到我的代码中。

epoch:我没有考虑到时间,因为需要删除超过某个日期的文件,花几个小时/分钟就会删除一天的文件,这意味着要保存。

限制

epoch认为你的短日期格式是YYYY-MM-DD。它需要适应其他设置或运行时计算(读取sShortTime,用户绑定配置,在过滤器中配置正确的字段顺序,并使用过滤器从参数中提取正确的数据)。

我说过我讨厌这个编辑器的自动格式化吗?它删除了空白行,复制粘贴是一个地狱。

我希望这能有所帮助。


看看我对类似问题的回答:

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"

这将删除比给定日期更早的文件。我相信它可以被修改为从当前日期往回走7天。

更新:我注意到HerbCSO已经改进了上面的脚本。我建议改用他的版本。


这个在7daysclean上的修改怎么样?CMD要把闰年考虑进去吗?

它可以在不到10行代码中完成!

set /a Leap=0
if (Month GEQ 2 and ((Years%4 EQL 0 and Years%100 NEQ 0) or Years%400 EQL 0)) set /a Leap=day
set /a Months=!_months!+Leap

Mofi编辑:

由于语法无效,由J.R.提供的上述条件总是计算为false。

GEQ 2月份也是错误的,因为在闰年里,只有3月到12月必须增加86400秒来增加一天,而2月则不行。

在批处理文件7天清理中考虑闰日的工作代码-仅在当前年份。Jay发布的cmd将是:

set "LeapDaySecs=0"
if %Month% LEQ 2 goto CalcMonths
set /a "LeapRule=Years%%4"
if %LeapRule% NEQ 0 goto CalcMonths
rem The other 2 rules can be ignored up to year 2100.
set /A "LeapDaySecs=day"
:CalcMonths
set /a Months=!_months!+LeapDaySecs

如果你有XP资源工具包,你可以使用robocopy将所有旧目录移动到一个目录中,然后使用rmdir删除其中一个:

mkdir c:\temp\OldDirectoriesGoHere
robocopy c:\logs\SoManyDirectoriesToDelete\ c:\temp\OldDirectoriesGoHere\ /move /minage:7
rmdir /s /q c:\temp\OldDirectoriesGoHere

我的命令是

forfiles -p "d:\logs" -s -m*.log -d-15 -c"cmd /c del @PATH\@FILE" 

@PATH -在我的例子中只是路径,所以我必须使用@PATH\@FILE

同样适用于文件/?对我来说也不行,但对于文件(没有“?”)工作得很好。

我唯一的问题是:如何添加多个掩码(例如“.log|.bak”)?

所有这些都是关于我在这里下载的forfiles.exe (win XP)

但如果你使用的是Windows服务器,forfiles.exe应该已经在那里,它是不同于ftp版本。这就是为什么我应该修改命令。

对于Windows Server 2003,我使用这个命令:

forfiles -p "d:\Backup" -s -m *.log -d -15 -c "cmd /c del @PATH"

复制这段代码并保存为DelOldFiles.vbs。

使用CMD: cscript //nologo DelOldFiles。于六月15日

“15”表示删除超过15天的文件。

  'copy from here
    Function DeleteOlderFiles(whichfolder)
       Dim fso, f, f1, fc, n, ThresholdDate
       Set fso = CreateObject("Scripting.FileSystemObject")
       Set f = fso.GetFolder(whichfolder)
       Set fc = f.Files
       Set objArgs = WScript.Arguments
       n = 0
       If objArgs.Count=0 Then
           howmuchdaysinpast = 0
       Else
           howmuchdaysinpast = -objArgs(0)
       End If
       ThresholdDate = DateAdd("d", howmuchdaysinpast, Date)   
       For Each f1 in fc
     If f1.DateLastModified<ThresholdDate Then
        Wscript.StdOut.WriteLine f1
        f1.Delete
        n = n + 1    
     End If
       Next
       Wscript.StdOut.WriteLine "Deleted " & n & " file(s)."
    End Function

    If Not WScript.FullName = WScript.Path & "\cscript.exe" Then
      WScript.Echo "USAGE ONLY IN COMMAND PROMPT: cscript DelOldFiles.vbs 15" & vbCrLf & "15 means to delete files older than 15 days in past."
      WScript.Quit 0   
    End If

    DeleteOlderFiles(".")
 'to here

执行如下命令:

ROBOCOPY C:\source C:\destination /mov /minage:7
del C:\destination /q

通过robocopy将所有文件(使用/mov移动文件,然后删除它们,而不是/ Move移动整个文件树,然后删除)移动到另一个位置,然后在该路径上执行删除命令,这样就可以了。

此外,如果你有一个目录中有很多数据,你可以使用/mir开关


forfiles /p "v:" /s /m *.* /d -3 /c "cmd /c del @path"

你应该做/d -3(3天前)这对我来说很好。所以所有复杂的批次都可以扔进垃圾桶。此外,forfile不支持UNC路径,因此可以通过网络连接到特定的驱动器。


使用forfiles。

有不同的版本。早期使用unix风格的参数。

我的版本(用于服务器2000 -注意交换机后面没有空格)-

forfiles -p"C:\what\ever" -s -m*.* -d<number of days> -c"cmd /c del @path"

要将forfiles添加到XP,请从ftp://ftp.microsoft.com/ResKit/y2kfix/x86/获取exe

并将其添加到C:\WINDOWS\system32


Windows Server 2008 R2操作系统

forfiles /P c:\sql_backups\ /S /M *.sql /D -90 /C "cmd /c del @PATH"

这将删除所有超过90天的.sql文件。


在我看来,JavaScript正在逐渐成为一种通用的脚本标准:它可能比任何其他脚本语言都适用于更多的产品(在Windows中,可以使用Windows脚本主机)。我必须清理旧文件在很多文件夹,所以这里是一个JavaScript函数来做:

// run from an administrator command prompt (or from task scheduler with full rights):  wscript jscript.js
// debug with:   wscript /d /x jscript.js

var fs = WScript.CreateObject("Scripting.FileSystemObject");

clearFolder('C:\\temp\\cleanup');

function clearFolder(folderPath)
{
    // calculate date 3 days ago
    var dateNow = new Date();
    var dateTest = new Date();
    dateTest.setDate(dateNow.getDate() - 3);

    var folder = fs.GetFolder(folderPath);
    var files = folder.Files;

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

        if( file.DateLastModified < dateTest)
        {
            var filename = file.name;
            var ext = filename.split('.').pop().toLowerCase();

            if (ext != 'exe' && ext != 'dll')
            {
                file.Delete(true);
            }
        }
    }

    var subfolders = new Enumerator(folder.SubFolders);
    for (; !subfolders.atEnd(); subfolders.moveNext())
    {
        clearFolder(subfolders.item().Path);
    }
}

对于每个要清除的文件夹,只需要对clearFolder()函数添加另一个调用。这个特定的代码还保存exe和dll文件,并清理子文件夹。


这没什么了不起的,但我今天需要做这样的事情,并按照预定的任务等运行它。

批处理文件,DelFilesOlderThanNDays.bat下面的示例exec w/ params:

DelFilesOlderThanNDays.bat 7 C:\dir1\dir2\dir3\logs *.log

echo off
cls
Echo(
SET keepDD=%1
SET logPath=%2 :: example C:\dir1\dir2\dir3\logs
SET logFileExt=%3
SET check=0
IF [%3] EQU [] SET logFileExt=*.log & echo: file extention not specified (default set to "*.log")
IF [%2] EQU [] echo: file directory no specified (a required parameter), exiting! & EXIT /B 
IF [%1] EQU [] echo: number of days not specified? :)
echo(
echo: in path [ %logPath% ]
echo: finding all files like [ %logFileExt% ]
echo: older than [ %keepDD% ] days
echo(
::
::
:: LOG
echo:  >> c:\trimLogFiles\logBat\log.txt
echo: executed on %DATE% %TIME% >> c:\trimLogFiles\logBat\log.txt
echo: ---------------------------------------------------------- >> c:\trimLogFiles\logBat\log.txt
echo: in path [ %logPath% ] >> c:\trimLogFiles\logBat\log.txt
echo: finding all files like [ %logFileExt% ] >> c:\trimLogFiles\logBat\log.txt
echo: older than [ %keepDD% ] days >> c:\trimLogFiles\logBat\log.txt
echo: ---------------------------------------------------------- >> c:\trimLogFiles\logBat\log.txt
::
FORFILES /p %logPath% /s /m %logFileExt% /d -%keepDD% /c "cmd /c echo @path" >> c:\trimLogFiles\logBat\log.txt 2<&1
IF %ERRORLEVEL% EQU 0 (
 FORFILES /p %logPath% /s /m %logFileExt% /d -%keepDD% /c "cmd /c echo @path"
)
::
::
:: LOG
IF %ERRORLEVEL% EQU 0 (
 echo:  >> c:\trimLogFiles\logBat\log.txt
 echo: deleting files ... >> c:\trimLogFiles\logBat\log.txt
 echo:  >> c:\trimLogFiles\logBat\log.txt
 SET check=1
)
::
::
IF %check% EQU 1 (
 FORFILES /p %logPath% /s /m %logFileExt% /d -%keepDD% /c "cmd /c del @path"
)
::
:: RETURN & LOG
::
IF %ERRORLEVEL% EQU 0 echo: deletion successfull! & echo: deletion successfull! >> c:\trimLogFiles\logBat\log.txt
echo: ---------------------------------------------------------- >> c:\trimLogFiles\logBat\log.txt

我认为e.James的答案很好,因为它适用于早于Windows 2000 SP4(可能更早)的未修改版本的Windows,但它需要写入外部文件。下面是一个修改后的版本,在保持兼容性的同时不创建外部文本文件:

REM del_old.cmd
REM usage: del_old MM-DD-YYYY
setlocal enabledelayedexpansion
for /f "tokens=*" %%a IN ('xcopy *.* /d:%1 /L /I null') do @if exist "%%~nxa" set "excludefiles=!excludefiles!;;%%~nxa;;"
for /f "tokens=*" %%a IN ('dir /b') do @(@echo "%excludefiles%"|FINDSTR /C:";;%%a;;">nul || if exist "%%~nxa" DEL /F /Q "%%a">nul 2>&1)

为了忠于最初的问题,如果你用天数作为参数调用它,它在一个脚本中为你做了所有的数学运算:

REM del_old_compute.cmd
REM usage: del_old_compute N
setlocal enabledelayedexpansion
set /a days=%1&set cur_y=%DATE:~10,4%&set cur_m=%DATE:~4,2%&set cur_d=%DATE:~7,2%
for /f "tokens=1 delims==" %%a in ('set cur_') do if "!%%a:~0,1!"=="0" set /a %%a=!%%a:~1,1!+0
set mo_2=28&set /a leapyear=cur_y*10/4
if %leapyear:~-1% equ 0 set mo_2=29
set mo_1=31&set mo_3=31&set mo_4=30&set mo_5=31
set mo_6=30&set mo_7=31&set mo_8=31&set mo_9=30
set mo_10=31&set mo_11=30&set mo_12=31
set /a past_y=(days/365)
set /a monthdays=days-((past_y*365)+((past_y/4)*1))&&set /a past_y=cur_y-past_y&set months=0
:setmonth
set /a minusmonth=(cur_m-1)-months
if %minusmonth% leq 0 set /a minusmonth+=12
set /a checkdays=(mo_%minusmonth%)
if %monthdays% geq %checkdays% set /a months+=1&set /a monthdays-=checkdays&goto :setmonth
set /a past_m=cur_m-months
set /a lastmonth=cur_m-1
if %lastmonth% leq 0 set /a lastmonth+=12
set /a lastmonth=mo_%lastmonth%
set /a past_d=cur_d-monthdays&set adddays=::
if %past_d% leq 0 (set /a past_m-=1&set adddays=)
if %past_m% leq 0 (set /a past_m+=12&set /a past_y-=1)
set mo_2=28&set /a leapyear=past_y*10/4
if %leapyear:~-1% equ 0 set mo_2=29
%adddays%set /a past_d+=mo_%past_m%
set d=%past_m%-%past_d%-%past_y%
for /f "tokens=*" %%a IN ('xcopy *.* /d:%d% /L /I null') do @if exist "%%~nxa" set "excludefiles=!excludefiles!;;%%~nxa;;"
for /f "tokens=*" %%a IN ('dir /b') do @(@echo "%excludefiles%"|FINDSTR /C:";;%%a;;">nul || if exist "%%~nxa" DEL /F /Q "%%a">nul 2>&1)

注意:上面的代码考虑了闰年,以及每个月的确切天数。唯一的最大值是从0/0/0开始的总天数(之后返回负年份)。

注意:数学只是单向的;它不能从负输入中正确地获得未来的日期(它会尝试,但可能会超过本月的最后一天)。


扩展aku的回答,我看到很多人在问北卡大学的路径。简单地将unc路径映射到驱动器号将使forfiles高兴。例如,驱动器的映射和取消映射可以在批处理文件中以编程方式完成。

net use Z: /delete
net use Z: \\unc\path\to\my\folder
forfiles /p Z: /s /m *.gz /D -7 /C "cmd /c del @path"

这将删除所有扩展名为.gz且超过7天的文件。如果你想确保Z:在使用它之前没有映射到任何其他东西,你可以做一些简单的事情

net use Z: \\unc\path\to\my\folder
if %errorlevel% equ 0 (
    forfiles /p Z: /s /m *.gz /D -7 /C "cmd /c del @path"
) else (
    echo "Z: is already in use, please use another drive letter!"
)

批处理文件经常需要解决与日期/时间相关的问题。但是命令行解释器cmd.exe没有计算日期/时间的功能。在Stack Overflow的其他页面和其他网站上已经发布了许多使用附加控制台应用程序或脚本的良好工作解决方案。

基于日期/时间的操作通常需要将日期/时间字符串转换为从确定日期开始的秒数。非常常见的是1970-01-01 00:00:00 UTC。但是也可以根据支持特定任务所需的日期范围使用任何稍后的日期。

杰伊发布了7天清洁。CMD包含一个快速的“日期到秒”解决方案的命令行解释器CMD .exe。但它没有考虑闰年的正确。J.R.发布了一个附加组件,将当年的闰日考虑在内,但忽略了基准年以来的其他闰年,即1970年以来的闰年。

我使用自20年来的静态表(数组),用一个小的C函数创建一次,以便快速获得从1970-01-01开始的日期/时间转换函数中的天数,包括闰日,在我用C/ c++编写的应用程序中。

这种非常快速的表方法也可以在批处理代码中使用FOR命令。因此,我决定编写批处理子例程GetSeconds,该子例程为传递给该例程的日期/时间字符串计算自1970-01-01 00:00:00 UTC以来的秒数。

注意:此处不考虑闰秒,因为Windows文件系统也不支持闰秒。

首先是表格:

Days since 1970-01-01 00:00:00 UTC for each year including leap days. 1970 - 1979: 0 365 730 1096 1461 1826 2191 2557 2922 3287 1980 - 1989: 3652 4018 4383 4748 5113 5479 5844 6209 6574 6940 1990 - 1999: 7305 7670 8035 8401 8766 9131 9496 9862 10227 10592 2000 - 2009: 10957 11323 11688 12053 12418 12784 13149 13514 13879 14245 2010 - 2019: 14610 14975 15340 15706 16071 16436 16801 17167 17532 17897 2020 - 2029: 18262 18628 18993 19358 19723 20089 20454 20819 21184 21550 2030 - 2039: 21915 22280 22645 23011 23376 23741 24106 24472 24837 25202 2040 - 2049: 25567 25933 26298 26663 27028 27394 27759 28124 28489 28855 2050 - 2059: 29220 29585 29950 30316 30681 31046 31411 31777 32142 32507 2060 - 2069: 32872 33238 33603 33968 34333 34699 35064 35429 35794 36160 2070 - 2079: 36525 36890 37255 37621 37986 38351 38716 39082 39447 39812 2080 - 2089: 40177 40543 40908 41273 41638 42004 42369 42734 43099 43465 2090 - 2099: 43830 44195 44560 44926 45291 45656 46021 46387 46752 47117 2100 - 2106: 47482 47847 48212 48577 48942 49308 49673 Calculating the seconds for year 2039 to 2106 with epoch beginning 1970-01-01 is only possible with using an unsigned 32-bit variable, i.e. unsigned long (or unsigned int) in C/C++. But cmd.exe use for mathematical expressions a signed 32-bit variable. Therefore the maximum value is 2147483647 (0x7FFFFFFF) which is 2038-01-19 03:14:07. Leap year information (No/Yes) for the years 1970 to 2106. 1970 - 1989: N N Y N N N Y N N N Y N N N Y N N N Y N 1990 - 2009: N N Y N N N Y N N N Y N N N Y N N N Y N 2010 - 2029: N N Y N N N Y N N N Y N N N Y N N N Y N 2030 - 2049: N N Y N N N Y N N N Y N N N Y N N N Y N 2050 - 2069: N N Y N N N Y N N N Y N N N Y N N N Y N 2070 - 2089: N N Y N N N Y N N N Y N N N Y N N N Y N 2090 - 2106: N N Y N N N Y N N N N N N N Y N N ^ year 2100 Number of days to first day of each month in current year. Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec Year with 365 days: 0 31 59 90 120 151 181 212 243 273 304 334 Year with 366 days: 0 31 60 91 121 152 182 213 244 274 305 335

使用这些表将日期转换为1970-01-01以来的秒数非常容易。

请注意!

日期和时间字符串的格式取决于Windows地区和语言设置。在GetSeconds的第一个FOR循环中,分配给环境变量Day、Month和Year的分隔符和令牌顺序必须在必要时适应本地日期/时间格式。

如果环境变量date中的日期格式与%%~tF上FOR命令使用的日期格式不同,则需要调整环境变量的日期字符串。

例如,当%DATE%扩展到Sun 02/08/2015,而%%~tF扩展到02/08/2015 07:38 PM,下面的代码可以通过修改第4行来使用:

call :GetSeconds "%DATE:~4% %TIME%"

这将导致只传递给子例程02/08/2015 -日期字符串,不包含3个字母的工作日缩写和分隔空格字符。

或者可以使用以下方法以正确的格式传递当前日期:

call :GetSeconds "%DATE:~-10% %TIME%"

现在日期字符串的最后10个字符被传递给函数GetSeconds,因此环境变量date的日期字符串是否有工作日并不重要,只要日和月总是以预期的顺序为2位数字,即格式为dd/mm/yyyy或dd.mm.yyyy。

下面是带有解释注释的批处理代码,它只是输出要删除的文件和要保留在C:\Temp文件夹树中的文件,请参阅第一个FOR循环的代码。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Get seconds since 1970-01-01 for current date and time.
call :GetSeconds "%DATE% %TIME%"
rem Subtract seconds for 7 days from seconds value.
set /A "LastWeek=Seconds-7*86400"

rem For each file in each subdirectory of C:\Temp get last modification date
rem (without seconds -> append second 0) and determine the number of seconds
rem since 1970-01-01 for this date/time. The file can be deleted if seconds
rem value is lower than the value calculated above.

for /F "delims=" %%# in ('dir /A-D-H-S /B /S "C:\Temp"') do (
    call :GetSeconds "%%~t#:0"
    set "FullFileName=%%#"
    setlocal EnableDelayedExpansion
    rem if !Seconds! LSS %LastWeek% del /F "!FullFileName!"
    if !Seconds! LEQ %LastWeek% (
        echo Delete "!FullFileName!"
    ) else (
        echo Keep   "!FullFileName!"
    )
    endlocal
)
endlocal
goto :EOF


rem No validation is made for best performance. So make sure that date
rem and hour in string is in a format supported by the code below like
rem MM/DD/YYYY hh:mm:ss or M/D/YYYY h:m:s for English US date/time.

:GetSeconds
rem If there is " AM" or " PM" in time string because of using 12 hour
rem time format, remove those 2 strings and in case of " PM" remember
rem that 12 hours must be added to the hour depending on hour value.

set "DateTime=%~1"
set "Add12Hours=0"
if not "%DateTime: AM=%" == "%DateTime%" (
    set "DateTime=%DateTime: AM=%"
) else if not "%DateTime: PM=%" == "%DateTime%" (
    set "DateTime=%DateTime: PM=%"
    set "Add12Hours=1"
)

rem Get year, month, day, hour, minute and second from first parameter.

for /F "tokens=1-6 delims=,-./: " %%A in ("%DateTime%") do (
    rem For English US date MM/DD/YYYY or M/D/YYYY
    set "Day=%%B" & set "Month=%%A" & set "Year=%%C"
    rem For German date DD.MM.YYYY or English UK date DD/MM/YYYY
    rem set "Day=%%A" & set "Month=%%B" & set "Year=%%C"
    set "Hour=%%D" & set "Minute=%%E" & set "Second=%%F"
)
rem echo Date/time is: %Year%-%Month%-%Day% %Hour%:%Minute%:%Second%

rem Remove leading zeros from the date/time values or calculation could be wrong.
if "%Month:~0,1%"  == "0" if not "%Month:~1%"  == "" set "Month=%Month:~1%"
if "%Day:~0,1%"    == "0" if not "%Day:~1%"    == "" set "Day=%Day:~1%"
if "%Hour:~0,1%"   == "0" if not "%Hour:~1%"   == "" set "Hour=%Hour:~1%"
if "%Minute:~0,1%" == "0" if not "%Minute:~1%" == "" set "Minute=%Minute:~1%"
if "%Second:~0,1%" == "0" if not "%Second:~1%" == "" set "Second=%Second:~1%"

rem Add 12 hours for time range 01:00:00 PM to 11:59:59 PM,
rem but keep the hour as is for 12:00:00 PM to 12:59:59 PM.
if %Add12Hours% == 1 if %Hour% LSS 12 set /A Hour+=12

set "DateTime="
set "Add12Hours="

rem Must use two arrays as more than 31 tokens are not supported
rem by command line interpreter cmd.exe respectively command FOR.
set /A "Index1=Year-1979"
set /A "Index2=Index1-30"

if %Index1% LEQ 30 (
    rem Get number of days to year for the years 1980 to 2009.
    for /F "tokens=%Index1% delims= " %%Y in ("3652 4018 4383 4748 5113 5479 5844 6209 6574 6940 7305 7670 8035 8401 8766 9131 9496 9862 10227 10592 10957 11323 11688 12053 12418 12784 13149 13514 13879 14245") do set "Days=%%Y"
    for /F "tokens=%Index1% delims= " %%L in ("Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N") do set "LeapYear=%%L"
) else (
    rem Get number of days to year for the years 2010 to 2038.
    for /F "tokens=%Index2% delims= " %%Y in ("14610 14975 15340 15706 16071 16436 16801 17167 17532 17897 18262 18628 18993 19358 19723 20089 20454 20819 21184 21550 21915 22280 22645 23011 23376 23741 24106 24472 24837") do set "Days=%%Y"
    for /F "tokens=%Index2% delims= " %%L in ("N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N") do set "LeapYear=%%L"
)

rem Add the days to month in year.
if "%LeapYear%" == "N" (
    for /F "tokens=%Month% delims= " %%M in ("0 31 59 90 120 151 181 212 243 273 304 334") do set /A "Days+=%%M"
) else (
    for /F "tokens=%Month% delims= " %%M in ("0 31 60 91 121 152 182 213 244 274 305 335") do set /A "Days+=%%M"
)

rem Add the complete days in month of year.
set /A "Days+=Day-1"

rem Calculate the seconds which is easy now.
set /A "Seconds=Days*86400+Hour*3600+Minute*60+Second"

rem Exit this subroutine.
goto :EOF

为了获得最佳性能,最好删除所有注释,即0-4个前导空格后以rem开头的所有行。

而且数组也可以做得更小,即减少时间范围从1980-01-01 00:00:00到2038-01-19 03:14:07,就像上面的批处理代码目前所支持的那样,例如从2015-01-01到2019-12-31,就像下面的代码所使用的那样,它会真正删除C:\Temp文件夹树中超过7天的文件。

此外,下面的批处理代码针对24小时时间格式进行了优化。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
call :GetSeconds "%DATE:~-10% %TIME%"
set /A "LastWeek=Seconds-7*86400"

for /F "delims=" %%# in ('dir /A-D-H-S /B /S "C:\Temp"') do (
    call :GetSeconds "%%~t#:0"
    set "FullFileName=%%#"
    setlocal EnableDelayedExpansion
    if !Seconds! LSS %LastWeek% del /F "!FullFileName!"
    endlocal
)
endlocal
goto :EOF

:GetSeconds
for /F "tokens=1-6 delims=,-./: " %%A in ("%~1") do (
    set "Day=%%B" & set "Month=%%A" & set "Year=%%C"
    set "Hour=%%D" & set "Minute=%%E" & set "Second=%%F"
)
if "%Month:~0,1%"  == "0" if not "%Month:~1%"  == "" set "Month=%Month:~1%"
if "%Day:~0,1%"    == "0" if not "%Day:~1%"    == "" set "Day=%Day:~1%"
if "%Hour:~0,1%"   == "0" if not "%Hour:~1%"   == "" set "Hour=%Hour:~1%"
if "%Minute:~0,1%" == "0" if not "%Minute:~1%" == "" set "Minute=%Minute:~1%"
if "%Second:~0,1%" == "0" if not "%Second:~1%" == "" set "Second=%Second:~1%"
set /A "Index=Year-2014"
for /F "tokens=%Index% delims= " %%Y in ("16436 16801 17167 17532 17897") do set "Days=%%Y"
for /F "tokens=%Index% delims= " %%L in ("N Y N N N") do set "LeapYear=%%L"
if "%LeapYear%" == "N" (
    for /F "tokens=%Month% delims= " %%M in ("0 31 59 90 120 151 181 212 243 273 304 334") do set /A "Days+=%%M"
) else (
    for /F "tokens=%Month% delims= " %%M in ("0 31 60 91 121 152 182 213 244 274 305 335") do set /A "Days+=%%M"
)
set /A "Days+=Day-1"
set /A "Seconds=Days*86400+Hour*3600+Minute*60+Second"
goto :EOF

有关Windows上的日期和时间格式以及文件时间比较的更多信息,请参阅我的回答:在批处理文件中查找文件是否超过4小时,并提供大量关于文件时间的附加信息。


请允许我在这条已经很有价值的线索上再做一点小小的贡献。我发现其他解决方案可能会摆脱实际的错误文本,但忽略了%ERRORLEVEL%,这表明我的应用程序失败。并且我合理地想要%ERRORLEVEL%,只要它不是“没有找到文件”错误。

一些例子:

具体地调试和消除错误:

forfiles /p "[file path...]\IDOC_ARCHIVE" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 |  findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&ECHO found error||echo found success

使用一个线性程序返回ERRORLEVEL成功或失败:

forfiles /p "[file path...]\IDOC_ARCHIVE" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 |  findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&EXIT /B 1||EXIT /B 0

在批处理文件的上下文中,在其他代码的中间使用一个线性程序来保持ERRORLEVEL为0 (ver > nul重置ERRORLEVEL):

forfiles /p "[file path...]\IDOC_ARCHIVE" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 |  findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&ECHO found error||ver > nul

对于SQL Server代理CmdExec作业步骤,我落在下面。我不知道这是否是一个错误,但该步骤中的CmdExec只识别第一行代码:

cmd /e:on /c "forfiles /p "C:\SQLADMIN\MAINTREPORTS\SQL2" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 |  findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&EXIT 1||EXIT 0"&exit %errorlevel%

对于windows 2012 R2,以下将工作:

    forfiles /p "c:\FOLDERpath" /d -30 /c "cmd /c del @path"

要查看将要删除的文件,请使用此命令

    forfiles /p "c:\FOLDERpath" /d -30 /c "cmd /c echo @path @fdate"

ROBOCOPY很适合我。最初建议我的伊曼。但是,与其将文件/文件夹移动到临时目录,然后删除临时文件夹的内容,不如将文件移动到垃圾桶!!

这是几行我的备份批处理文件的例子:

SET FilesToClean1=C:\Users\pauls12\Temp
SET FilesToClean2=C:\Users\pauls12\Desktop\1616 - Champlain\Engineering\CAD\Backups

SET RecycleBin=C:\$Recycle.Bin\S-1-5-21-1480896384-1411656790-2242726676-748474

robocopy "%FilesToClean1%" "%RecycleBin%" /mov /MINLAD:15 /XA:SH /NC /NDL /NJH /NS /NP /NJS
robocopy "%FilesToClean2%" "%RecycleBin%" /mov /MINLAD:30 /XA:SH /NC /NDL /NJH /NS /NP /NJS

它可以清除“Temp”文件夹中超过15天的文件,以及AutoCAD备份文件夹中超过30天的文件。我使用变量是因为行可以很长,我可以在其他位置重用它们。您只需要找到与您的登录相关联的回收站的dos路径。

这是在我的工作电脑上运行的。我知道你们中的一些人可能有更严格的权利,但无论如何都要尝试一下;)ROBOCOPY参数说明请在“谷歌”中查询。

干杯!


这一个帮我做到了。它有一个日期,你可以减去想要的数量,回到过去的时间:

@echo off

set m=%date:~-7,2%
set /A m
set dateYear=%date:~-4,4%
set /A dateYear -= 2
set DATE_DIR=%date:~-10,2%.%m%.%dateYear% 

forfiles /p "C:\your\path\here\" /s /m *.* /d -%DATE_DIR% /c "cmd /c del @path /F"

pause

cmd /c del @path /F中的/F强制删除特定文件,在某些情况下,该文件可以是只读的。

dateYear是年份变量,您可以根据自己的需要更改减号


我的脚本删除文件早于特定年份:

@REM _______ GENERATE A CMD TO DELETE FILES OLDER THAN A GIVEN YEAR
@REM _______ (given in _olderthanyear variable)
@REM _______ (you must LOCALIZE the script depending on the dir cmd console output)
@REM _______ (we assume here the following line's format "11/06/2017  15:04            58 389 SpeechToText.zip")

@set _targetdir=c:\temp
@set _olderthanyear=2017

@set _outfile1="%temp%\deleteoldfiles.1.tmp.txt"
@set _outfile2="%temp%\deleteoldfiles.2.tmp.txt"

  @if not exist "%_targetdir%" (call :process_error 1 DIR_NOT_FOUND "%_targetdir%") & (goto :end)

:main
  @dir /a-d-h-s /s /b %_targetdir%\*>%_outfile1%
  @for /F "tokens=*" %%F in ('type %_outfile1%') do @call :process_file_path "%%F" %_outfile2%
  @goto :end

:end
  @rem ___ cleanup and exit
  @if exist %_outfile1% del %_outfile1%
  @if exist %_outfile2% del %_outfile2%
  @goto :eof

:process_file_path %1 %2
  @rem ___ get date info of the %1 file path
  @dir %1 | find "/" | find ":" > %2
  @for /F "tokens=*" %%L in ('type %2') do @call :process_line "%%L" %1
  @goto :eof

:process_line %1 %2
  @rem ___ generate a del command for each file older than %_olderthanyear%
  @set _var=%1
  @rem  LOCALIZE HERE (char-offset,string-length)
  @set _fileyear=%_var:~0,4%
  @set _fileyear=%_var:~7,4%
  @set _filepath=%2
  @if %_fileyear% LSS %_olderthanyear% echo @REM %_fileyear%
  @if %_fileyear% LSS %_olderthanyear% echo @del %_filepath%
  @goto :eof

:process_error %1 %2
  @echo RC=%1 MSG=%2 %3
  @goto :eof

天啊,已经有很多答案了。我发现的一个简单而方便的方法是使用&参数从单个Windows命令行指令连续执行两次ROBOCOPY.EXE。

ROBOCOPY.EXE SOURCE-DIR TARGET-DIR *.* /MOV /MINAGE:30 & ROBOCOPY.EXE SOURCE-DIR TARGET-DIR *.* /MOV /MINAGE:30 /PURGE

在这个例子中,它的工作原理是选择所有超过30天的文件(.)并将它们移动到目标文件夹。第二个命令再次执行相同的操作,添加了PURGE命令,这意味着删除目标文件夹中不存在于源文件夹中的文件。 因此,从本质上讲,第一个命令移动文件,第二个命令删除文件,因为当调用第二个命令时,它们不再存在于源文件夹中。

在测试时,请参考ROBOCOPY的文档并使用/L开关。


更灵活的方法是使用FileTimeFilterJS.bat:

@echo off

::::::::::::::::::::::
set "_DIR=C:\Users\npocmaka\Downloads"
set "_DAYS=-5"
::::::::::::::::::::::

for /f "tokens=* delims=" %%# in ('FileTimeFilterJS.bat  "%_DIR%" -dd %_DAYS%') do (
    echo deleting  "%%~f#"
    echo del /q /f "%%~f#"
)

该脚本将允许您使用诸如日、分、秒或小时等测量。 选择weather按创建、访问或修改时间筛选文件 列出某个日期之前或之后(或两个日期之间)的文件 选择是显示文件还是dirs(或两者都显示) 递归与否


删除所有超过3天的文件

forfiles -p "C:\folder" -m *.* -d -3 -c "cmd  /c del /q @path"

删除超过3天的目录

forfiles -p "C:\folder" -d -3 -c "cmd  /c IF @isdir == TRUE rd /S /Q @path"