批处理文件以删除超过N天的文件

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

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

1300898 次浏览

享受:

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

有关更多详细信息,请参阅forfiles留档

有关更多好东西,请参阅Windows XP命令行的A-Z索引

如果您的计算机上没有安装forfiles,请将其从任何WindowsServer2003复制到位于%WinDir%\system32\的Windows XP计算机上。这是可能的,因为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时代替换的版本,仅限于日常使用(没有时间保留):

7daysclean.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行代码的想法,请继续发布,所以我将其添加到我的代码中。

时代:我没有考虑时间,因为需要删除早于某个日期的文件,花费数小时/分钟会删除一天中用于保存的文件。

限制

时代理所当然地认为您的短日期格式是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"

这会删除早于给定日期的文件。我相信它可以被修改为从当前日期回溯七天。

更新:我注意到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.贡献的条件总是计算为虚假

而且Month GEQ 2也是错误的,因为增加86400秒的一天必须在闰年中完成,只有3月到12月,而不是2月。

Jay发布的批处理文件7daysclean.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资源工具包,您可以使用机器人复制将所有旧目录移动到一个目录中,然后使用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

还有forfiles /?也不适合我,但是forfiles(没有“?”)工作正常。

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

所有这一切关于forfiles.exe我这里下载(在赢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.vbs 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

移动所有文件(使用 /mov,移动文件,然后删除它们,而不是 /move移动整个文件,然后删除)通过机器人复制到另一个位置,然后在该路径上执行删除命令,你都很好。

此外,如果您有一个包含大量数据的目录,您可以使用/mir开关

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

你应该做/d -3(3天前)这对我来说很好。所以所有复杂的批次都可能在垃圾箱中。此外forfiles不支持UNC路径,所以要与特定驱动器建立网络连接。

使用文件。

有不同的版本。早期的使用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\system 32

对于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.bat7C:\dir 1\dir 2\dir 3\logs*.日志

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

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

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路径。简单地将unc路径映射到驱动器号会让forfile感到高兴。例如,驱动器的映射和取消映射可以在批处理文件中以编程方式完成。

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。但也可以使用任何较晚的一天,具体取决于支持特定任务所需的日期范围。

Jay发布了7daysclean.cmd,其中包含命令行解释器cmd.exe的快速“日期到秒”解决方案。但它没有正确考虑闰年。J. R.发布了附加,因为它考虑了当年的闰日,但忽略了自基准年以来的其他闰年,即自1970年以来。

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

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

备注:飞跃秒不考虑在内,因为Windows文件系统也不支持飞跃秒。

首先是表格:

  1. 自1970-01-01 00:00:00 UTC以来的天数,包括闰日。

    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
    

    从1970-01-01开始计算2039年到2106年的秒数只能使用无符号32位变量,即C/C++中的无符号long(或无符号int)。

    但是cmd.exe对数学表达式使用有符号的32位变量。因此最大值为2147483647(0x7FFFFFFF),即2038-01-19 03:14:07。

  2. 1970年至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
    
  3. 当前年份到每月第一天的天数。

                       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循环中的环境变量DayMonthYear的标记顺序必须根据需要调整为本地日期/时间格式。

如果环境变量日期中的日期格式与%%~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,因此环境变量日期的日期字符串是否带有或不带有工作日并不重要,只要日和月始终以预期的顺序具有2位数字,即格式dd/mm/yyyydd.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

使用oneliner返回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

使用oneliner将ERRORLEVEL保持在零,以便在其他代码中的批处理文件上下文中成功(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

对于SQLServer Agent CmdExec作业步骤,我执行了以下操作。我不知道这是否bug,但步骤中的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"

机器人对我来说很棒。最初建议我的Iman。但不是将文件/文件夹移动到临时目录,然后删除临时文件夹的内容,将文件移动到垃圾桶!!!

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

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路径。

这对我来说是在工作电脑上,它可以工作。我知道你们中的一些人可能有更严格的权利,但无论如何都要试一试;)在Google上搜索有关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天的文件(.)并将它们移动到目标文件夹。第二个命令通过添加净化命令再次执行相同的操作,这意味着删除目标文件夹中不存在于源文件夹中的文件。 所以本质上,第一个命令MOVES文件和第二个DELETES,因为当调用第二个命令时,它们不再存在于源文件夹中。

请参阅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#"
)

该脚本将允许您使用天、分钟、秒或小时等测量值。 选择天气按创建、访问或修改时间过滤文件 列出某个日期之前或之后(或两个日期之间)的文件 选择是否显示文件或目录(或两者兼而有之) 递归与否

删除所有超过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"