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


677

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

只需几行代码即可在BASH完成类似的操作。似乎可以对Windows中的批处理文件至少进行一些远程操作。我正在寻找一种可以在标准Windows命令提示符下运行且没有任何其他实用程序的解决方案。请不要使用PowerShell或Cygwin。


8
Jeff Atwood在Serverfault上回答了这个问题,我认为应该在此处进行记录。serverfault.com/questions/49614/delete-files-older-than-x-days
Dusty

只有已经张贴在这里设在使用内部CMD.EXE命令.bat文件的新方法:stackoverflow.com/questions/9746778/...
Aacini

1
gehrcke.de/timegaps就是为此目的而设计的。它甚至允许使用更复杂的删除方案:除了保留最近7天的文件外,例如还允许在最近8周,12个月,2年中的每个文件中保留一个文件。
Jan-Philip Gehrcke博士2014年

Answers:


1071

请享用:

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

有关更多详细信息,请参见forfiles文档

有关更多信息,请参阅Windows XP命令行的AZ索引

如果您尚未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"

12
应该是del @FILE,区分大小写另外我建议使用/ c echo @FILE进行测试
Russell Steen

40
@Russell:@PATH是完整路径,包括名称。@FILE只是名称,因此,如果您要处理子文件夹,它将无法工作。
gregmac

86
请注意,如果您希望文件的日期早于10天,则需要指定-d“ -10”。-ve表示“大于”,+ ve表示“大于”。您还可以将DDMMYY或-DDMMYY格式指定为-d的参数。
gregmac

42
我在Win Server 2008上使用了以下语法:forfiles / P“ C:\ Mysql_backup” / S / M * .sql / D -30 / C“ cmd / c del
@PATH

9
当“早于7天”被定义为“修改超过7天”而不是“创建超过7天”时,此答案有效。后者如何实现?
TimS

76

运行以下命令

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

通过robocopy将所有文件(使用/ mov移动文件,然后将其删除,而不是/ move移动整个文件树,然后删除它们)通过robocopy移至另一个位置,然后在该路径上执行delete命令,您就全部好。

另外,如果您的目录中包含大量数据,则可以使用/mirswitch


5
在大多数情况下,这是一个不切实际的答案。如果我的目录中包含大量数据,则无法正常运行。我会选择“就地”的答案之一
adamb0mb

5
@ adamb0mb这绝不是不切实际的-如果“目标”“源”在同一文件系统上,则移动操作非常轻巧。由于robocopy 确实很健壮,因此实际上它适用于任何目录大小,晦涩的文件名,基本上任意的路径长度,并在需要时包含目录-对于许多其他Windows实用程序肯定不能说这些。不过,如果您希望遇到文件名问题,我会使用rd /s /q c:\destination而不是del命令,甚至使用另一次robocopy /mir c:\emptydir c:\destination运行来清空目录。
syneticon-dj

12
另外,robocopy确实支持UNC路径- forfiles从接受的答案中不会这样做。
syneticon-dj

3
我的想法更像是:“我的文件已经在我想要的位置了。我不想移动它们。” “从逻辑上说,删除文件就是您正在做的事,所以这样做。不要使Robocopy超载去做”
adamb0mb 2013年

3
我建议使用这种单行代码来查看C:\test7天以上的所有文件。要删除文件,请更改echodelforfiles /p "C:\test" /m "*.*" /c "cmd /c echo @file" /D -7
PowerUser

25

Ok有点无聊,并提出了这个建议,其中包含我的一个穷人的Linux时代替换版本,该版本仅限于日常使用(无时间限制):

7天清理

@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,用户绑定配置,在过滤器中配置适当的字段顺序并使用过滤器从参数中提取正确的数据)。

我是否提到我讨厌该编辑器的自动格式化?它删除了空白行,并且复制粘贴是一个地狱。

我希望这有帮助。


4
+1为非破坏性代码,当我自己提供代码示例时,我会尽量记住这一点。
Haugholt 2014年

5
很晚了,完全没有关联,但是7daysclean.cmd听起来像是Synth-Punk乐队的一个了不起的名字。
Flonk

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

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


3
与其他答案(包括已接受的答案)相同的错误。这种奇怪的指定习惯是*.*从哪里来的?通配符*.*不匹配Windows中的所有文件。它仅匹配.名称中带有的文件。OP从未.对文件名中的要求进行任何说明。正确的参数是/M *,但这仍然是默认设置。完全没有必要/M
AnT

@AnT:您确定吗?我认为*.*行为与*Windows 完全相同。实际上,我只是在我的计算机上尝试过,dir *.*实际上列出test file了一个没有扩展名的文件。
安德烈亚斯·瑞布兰德

1
@Andreas Rejbrand:我也感到很惊讶,但是*.*dir-m选择之间并不一致forfiles。该-m *.*面膜的确将跳过扩展名的文件名,如我上面我的评论(尝试一下)表示。有趣的是,MS文档明确声明-m *.*了默认值。但是,如果您在现实生活中尝试过,您会发现默认设置实际上是-m *-所有文件都经过迭代。
AnT

1
该MS文档页面-technet.microsoft.com/zh-cn/library/cc753551(v=ws.11).aspx-包含大量错误(例如,示例中),因为该文档的作者错误地认为*.*应用了掩码所有文件。我对“这个奇怪的习惯” rethorical问题确实是多余的,因为治疗*.**等同是一个长期的Windows约定。但是,由于某些原因,/min选项forfiles可能违反了该约定。
AnT


18

看看我的回答到一个类似的问题

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在上述脚本上有所改进。我建议改用他的版本


12

我的命令是

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

@PATH -就我而言只是路径,所以我不得不使用 @PATH\@FILE

forfiles /?没有为我工作,但forfiles(没有“?”)工作得很好。

我唯一的问题是:如何添加多个掩码(例如“ .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"

9

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

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

Jay发布了7daysclean.cmd,其中包含用于命令行解释器cmd.exe的快速“日期到秒”解决方案。但这并没有考虑到正确的leap年。JR发布了当前current日纳入考虑范围的附加组件,但忽略了自基准年(即1970年以来)以来的其他leap年。

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

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

注意:由于Windows文件系统也不支持leap秒,因此不考虑Le秒。

首先,表:

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

    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
    

    只有使用无符号的32位变量(即C / C ++中的无符号长(或无符号int)),才能计算从1970年1月1日开始的2039年到2106年的秒数。

    但是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区域和语言设置。分隔符和分配给环境变量令牌的顺序DayMonthYear在第一FOR的循环GetSeconds如果需要的话,必须适应当地的日期/时间格式。

如果环境变量DATE中的日期格式不同于命令FOR on 使用的日期格式,则必须调整环境变量的日期字符串%%~tF

例如,当%DATE%expands to Sun 02/08/2015while %%~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/yyyydd.mm.yyyy

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

@echo off
setlocal EnableExtensions EnableDelayedExpansion
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=" %%F in ('dir /A-D-H-S /B /S "C:\Temp"') do (
    call :GetSeconds "%%~tF:0"
    rem if !Seconds! LSS %LastWeek% del /F "%%~fF"
    if !Seconds! LEQ %LastWeek% (
        echo Delete "%%~fF"
    ) else (
        echo Keep   "%%~fF"
    )
)
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 "%DateTime: AM=%" NEQ "%DateTime%" (
    set "DateTime=%DateTime: AM=%"
) else if "%DateTime: PM=%" NEQ "%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%"  EQU "0" ( if "%Month:~1%"  NEQ "" set "Month=%Month:~1%"   )
if "%Day:~0,1%"    EQU "0" ( if "%Day:~1%"    NEQ "" set "Day=%Day:~1%"       )
if "%Hour:~0,1%"   EQU "0" ( if "%Hour:~1%"   NEQ "" set "Hour=%Hour:~1%"     )
if "%Minute:~0,1%" EQU "0" ( if "%Minute:~1%" NEQ "" set "Minute=%Minute:~1%" )
if "%Second:~0,1%" EQU "0" ( if "%Second:~1%" NEQ "" 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 2 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 EnableDelayedExpansion
call :GetSeconds "%DATE:~-10% %TIME%"
set /A "LastWeek=Seconds-7*86400"

for /F "delims=" %%F in ('dir /A-D-H-S /B /S "C:\Temp"') do (
    call :GetSeconds "%%~tF:0"
    if !Seconds! LSS %LastWeek% del /F "%%~fF"
)
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%"  EQU "0" ( if "%Month:~1%"  NEQ "" set "Month=%Month:~1%"   )
if "%Day:~0,1%"    EQU "0" ( if "%Day:~1%"    NEQ "" set "Day=%Day:~1%"       )
if "%Hour:~0,1%"   EQU "0" ( if "%Hour:~1%"   NEQ "" set "Hour=%Hour:~1%"     )
if "%Minute:~0,1%" EQU "0" ( if "%Minute:~1%" NEQ "" set "Minute=%Minute:~1%" )
if "%Second:~0,1%" EQU "0" ( if "%Second:~1%" NEQ "" 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个小时的答案,其中包含有关文件时间的许多其他信息。


9

复制此代码并将其另存为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

8

对于Windows Server 2008 R2:

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

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


7

使用forfiles。

有不同的版本。早期的使用unix样式参数。

我的版本(对于服务器2000-注意切换后没有空格)-

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

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

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


11
@Kibbee答案不一样,语法也不同。这是天才的尝试。我对Windows命令行知之甚少,花了数小时的挫败感才能使它正常工作。对我来说,最重要的信息是存在不同的版本(具有不同的语法),并且需要删除空格。这些东西都不包含在原始答案中。(我会回答这个问题,但我没有特权
Aidan Ewen

与其他答案(包括已接受的答案)相同的错误。通配符*.*forfiles不匹配的所有文件。它只匹配.名称中带有的文件(即带有扩展名的文件)。OP从未.对文件名中的要求进行任何说明。正确的参数是/M *,但这仍然是默认设置。完全没有必要/M
AnT

7

对于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"

在Windows Server 2008及以上版本和Windows 7这甚至作品
kwrl

6

IMO,JavaScript正在逐渐成为一种通用的脚本标准:它可能比其他任何脚本语言在更多的产品中可用(在Windows中,可以使用Windows Scripting Host获得)。我必须清理许多文件夹中的旧文件,因此这是一个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文件,并清理子文件夹。


6

考虑到a年,对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编辑:

由于语法无效,JR贡献的上述条件始终评估为false

Month GEQ 2也是错误的,因为必须在a年中仅在3月到12月的几个月中增加一天增加86400秒,而不是在2月。

Jay发布的批处理文件7daysclean.cmd中的工作代码(仅在当年)将leap日考虑在内:

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

5

我可能会对这个已经有价值的线程做出微不足道的贡献。我发现其他解决方案可能会摆脱实际的错误文本,但忽略了%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

对于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%

5

天哪,已经有很多答案了。我发现的一种简单方便的方法是,使用参数从一条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开关。


4

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

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

4

我认为e.James的答案很好,因为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)

注意:上面的代码考虑了leap年,以及每个月中的确切天数。唯一的最大值是自0/0/0以来的总天数(此后返回负数年)。

注意:数学只能以一种方式进行;它不能正确地从负输入中获取将来的日期(可以尝试,但可能会超过该月的最后一天)。


3

您也许可以做到这一点。您可以看一下这个问题,作为一个简单的例子。当您开始比较日期时,就会变得很复杂。判断日期是否更大可能很容易,但是有很多情况需要考虑是否需要实际获得两个日期之间的差额。

换句话说-除非您真的不能使用第三方工具,否则不要尝试发明它。


3

这没什么了不起的,但是我今天需要做这样的事情并将其作为计划任务运行,等等。

批处理文件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

3

在扩展aku的答案时,我看到很多人在问UNC路径。只需将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!"
)

3

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

对我来说,这是在工作计算机上,并且可以工作。我们了解到,有些人可能拥有更多的限制性权利,但还是请尝试一下;)搜索Google以获取有关ROBOCOPY参数的说明。

干杯!


1
现有的倒数第二个答案也支持RoboCopy。当然,您使用了一些不同的选项,但这与现有答案很接近。
乔纳森·莱夫勒

2
该帖子具有新内容-将文件移动到回收站。Robocopy尚未提出该建议,它使用内置的单行命令完全回答了原始帖子。与可以使用“ DEL”和“ RMDIR”命令进行组合相比,它们的工作效果更好,因为可以从回收站中还原文件。嘿,我还是这里的新人,请休息一下;)
肖恩·保利森

2

我删除特定年份之前的文件的脚本:

@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

1

这是为我做的。它与日期配合使用,您可以减去所需的年份数以返回时间:

@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

/Fcmd /c del @path /F部队的具体文件中的一些文件可以是只读的情况下被删除。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.