批处理文件删除N天前的文件

746

我正在寻找一种在批处理文件中删除所有早于7天的文件的方法。我在网上搜索过,并发现有些示例代码有数百行,而其他代码则需要安装额外的命令行工具来完成该任务。

在Bash中可以用几行代码完成类似的事情。看起来至少有点简单的东西可以在Windows的批处理文件中完成。我正在寻找在标准的Windows命令提示符中解决问题的解决方案,不需要任何额外的工具。请不要使用PowerShell或Cygwin。


8
Jeff Atwood在Serverfault上回答了这个问题,我认为应该在这里记录一下。http://serverfault.com/questions/49614/delete-files-older-than-x-days - Dusty
这里发布了一种基于 .BAT 文件的新方法,仅使用内部 CMD.EXE 命令:https://dev59.com/PmHVa4cB1Zd3GeqPoqSp#9747065 - Aacini
1
http://gehrcke.de/timegaps就是为此目的而设计的。它甚至允许更复杂的删除方案:除了保留最近7天的文件外,还可以保留每个最近8周、12个月、2年的一个文件。 - Dr. Jan-Philip Gehrcke
25个回答

9
针对Windows Server 2008 R2操作系统:
forfiles /P c:\sql_backups\ /S /M *.sql /D -90 /C "cmd /c del @PATH"

这将删除所有早于90天的.sql文件。

7

使用forfiles命令。

不同的版本有所不同。早期版本采用Unix风格参数。

我的版本(适用于Server 2000-注意开关后没有空格)-

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

如果想在XP系统中使用forfiles,可以从ftp://ftp.microsoft.com/ResKit/y2kfix/x86/下载exe文件,并将其添加到C:\WINDOWS\system32目录中。


11
@Kibbee 这不是相同的答案,语法是不同的。这是一个真诚的尝试来帮助。由于对Windows命令行了解甚少,我花了几个小时的时间感到沮丧才让它工作。对我来说关键的信息是存在不同版本(有不同的语法),而且我需要去掉空格。这些都没有包含在原始答案中。(我本来想在回答中评论,但我没有足够的权限。) - Aidan Ewen
与其他答案(包括被接受的答案)相同的错误。在 forfiles 中,通配符 *.* 并不匹配 所有 文件。它只匹配文件名中带有 . 的文件(即带有扩展名的文件)。原始问题并没有提到需要文件名中带有 .。正确的参数是 /M *,但这实际上已经是默认值了。根本不需要使用 /M - AnT stands with Russia

6

我认为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
我很荣幸能为这个有价值的帖子增添一点贡献。我发现其他解决方案可能会消除实际的错误文本,但却忽略了%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为零以实现成功,同时不影响其他代码(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 Agent 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%

6

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

Month GEQ 2也是错误的,因为只有在闰年3月到12月之间的那个月,才需要添加86400秒以获得更多一天的时间,而对于二月份则不需要。

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

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的回答很好,因为它可以在未经修改的Windows版本上使用,早至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以来经过的天数(之后它会返回负数年份)。

注意:这种数学计算只能单向进行;无法从负输入中正确获取未来日期(它会尝试,但可能会超出该月的最后一天)。


4

在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"

这将删除7天前的所有扩展名为.gz的文件。如果您想在使用之前确保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!"
)

嗨!九年过去了,这个答案解决了我两天前的搜索问题!谢谢你! - JPSeagull
嗨!九年过去了,这个答案解决了我两天前的搜索!谢谢你! - undefined

4

ROBOCOPY 对我来说非常有效。这是由我朋友 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参数的解释。干杯!

1
现有的得票第二名的答案也支持RoboCopy。尽管你使用的选项略有不同,但它与现有答案相近。 - Jonathan Leffler
2
这篇文章有一个新内容——将文件移动到回收站。这还没有使用Robocopy提出,它完全使用内置的单行命令回答了原始帖子。比组合“DEL”和“RMDIR”命令更好,因为文件可以从回收站中恢复。嘿,我还是新手——给我点时间;) - Shawn Pauliszyn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接