如何删除具有多个文件夹组的文件夹中的一组文件夹中最旧的文件夹?

时间:2017-11-16 17:22:51

标签: batch-file

文件夹20171113.224424 15.11.2017 17:24 20171113.224421 16.11.2017 15:26 20171113.224412 16.11.2017 15:33 20171112.424424 16.11.2017 15:33 20171112.224424 16.11.2017 15:33 20171112.221424 16.11.2017 15:34 20171111.224428 16.11.2017 15:34 20171111.224427 16.11.2017 15:35 20171111.224424 16.11.2017 15:34 包含以下列出的子文件夹,其中包含Windows资源管理器中显示的名称(左)和上次修改日期(右):

.

我需要一个批处理脚本来检查是否有两个以上的文件夹,其中包含20171113.22442420171113.224421和{{ 1}}。

批处理文件应保留最新的两个具有相同日期字符串的文件夹,并使用文件夹创建日期而不是上次修改日期删除所有其他旧文件夹。

对于上面的示例,创建日期等于上次修改日期,要删除的文件夹为:

20171113.224412

当两个文件夹具有相同的创建日期时,如果可能,则应删除点后面较小编号的文件夹。

其余文件夹是:

20171113.224424
20171112.224424
20171111.224424

我尝试了很多代码,但我不会在这里发布所有代码。

我的代码列出了目录中的所有文件夹,但找不到使用相同的前8个字母对文件夹进行分组的方法:

20171113.224421
20171113.224412
20171112.424424
20171112.221424
20171111.224428
20171111.224427

如果有常规分组,我编写代码跳过最后10行,并删除我不需要的文件夹,如上所述:

@echo off
set back=%cd%
for /d %%i in (d:\backup\*) do (
    cd "%%i"
    echo current directory:
    cd
    pause
)
cd %back%

1 个答案:

答案 0 :(得分:0)

此任务的批处理文件为:

@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "BackupFolder=D:\backup"
set "LastDate="
for /F "delims=." %%I in ('dir "%BackupFolder%\????????.*" /AD /B /ON 2^>nul') do (
    if not "!LastDate!" == "%%I" (
        for /F "skip=2 delims=" %%D in ('dir "%BackupFolder%\%%I.*" /AD /B /O-D-N /TC') do rd /Q /S "%BackupFolder%\%%D"
        set "LastDate=%%I"
    )
)
endlocal

第一个外部 FOR 在一个单独的命令进程中执行,后面以cmd /c开头,在第一个括号中指定的 DIR 命令行,并捕获输出的所有内容 DIR 处理 STDOUT 以便稍后逐行处理。

使用的 DIR 命令输出

  • 由于????????.*(属性目录)
  • ,仅匹配通配符模式/AD的目录 由于/B(裸格式),
  • 只有他们的名字没有路径
  • 由于/ON(按名称排序)按名称排序。

备份文件夹当前可能不包含与此模式匹配的文件夹。在这种情况下, DIR 会输出错误消息以处理 STDERR ,由于包含文件而不是目录。此可能的错误消息将重定向到设备 NUL 以禁止它。

阅读有关Using Command Redirection Operators的Microsoft文章,了解2>nul的说明。重定向运算符>必须使用 FOR 命令行上的插入符^进行转义,以便在执行命令之前Windows命令解释程序处理此命令行时将其解释为文字字符FOR ,它在后台启动的单独命令进程中执行 DIR 命令行。

FOR 处理捕获的行,忽略空行和以分号开头的行。这样的线路在这里不存在,所以没问题。使用.作为分隔符将每个(其他)行拆分为两个字符串。只有每行第一个.的第一个字符串被分配给循环变量I,该变量在下一个执行的命令行中使用。

在此处使用命令 DIR 来获取由 FOR 处理的目录列表在循环执行期间未被修改而不是使用会读取的for /D非常重要在循环的每次迭代中直接从文件系统获取下一个目录名称。循环执行期间目录列表会更改。使用for /D时,由于处理目录时目录列表更改,可能会跳过某些目录。

IF 条件使用延迟环境变量扩展进行简单区分大小写的字符串比较,以将先前处理的文件夹的日期字符串与当前文件夹进行比较。仅在上次处理的文件夹的日期与当前文件夹的日期之间的差异上执行内部循环。此 IF 条件仅用于使文件夹删除过程更快一些。

此处使用延迟环境环境变量扩展没有问题,因为备份文件夹中没有文件夹在文件夹名称中包含感叹号。

第二个,内部 FOR 循环也运行命令 DIR 以获取目录列表,其中包含当前文件夹的日期字符串及其名称,但这次是第一次反向按创建日期排序,如果两个或多个文件夹具有相同的创建日期,则由于/O-D-N(按日期排序倒退,下一个按名称倒退)和/TC(时间:创建)排序,按名称排序。反向日期顺序表示首先输出最新目录,最后输出最旧目录。

内部 FOR 循环处理由 DIR 输出的捕获线,并跳过前两行,这意味着忽略两个最新的文件夹。由于delims=(空分隔符列表),处理其他行而不分割行,因此 DIR 输出的完整文件夹名称被分配给循环变量D

命令 RD 会静默删除循环变量D中保存名称的文件夹,因为/Q/S而包含所有文件和子文件夹。

然后将当前文件夹的日期字符串分配给环境变量LastDate,以跳过具有相同日期字符串的外部 FOR 的目录列表中的所有文件夹。

也可以使用单个命令行而不使用延迟环境变量扩展稍微慢一点,这也适用于名称中!的文件夹。

@for /F "delims=." %%I in ('dir "D:\backup\????????.*" /AD /B /ON 2^>nul') do @for /F "skip=2 delims=" %%D in ('dir "D:\backup\%%I.*" /AD /B /O-D-N /TC') do @rd /Q /S "D:\backup\%%D"

要了解使用的命令及其工作原理,请打开命令提示符窗口,执行以下命令,并完全阅读为每个命令显示的所有帮助页面。

  • dir /?
  • echo /?
  • endlocal /?
  • for /?
  • if /?
  • rd /?
  • set /?
  • setlocal /?

<强>更新

增强版本在删除备份目录之前记录具有完整路径的所有文件的名称。

@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "BackupFolder=D:\backup"
set "LastDate="
set "LogFile=%BackupFolder%\DeletedFiles.log"
for /F "delims=." %%I in ('dir "%BackupFolder%\????????.*" /AD /B /ON 2^>nul') do (
    if not "!LastDate!" == "%%I" (
        for /F "skip=2 delims=" %%D in ('dir "%BackupFolder%\%%I.*" /AD /B /O-D-N /TC') do (
            dir "%BackupFolder%\%%D" /A-D /B /ON /S >>"%LogFile%" 2>nul
            rd /Q /S "%BackupFolder%\%%D"
        )
        set "LastDate=%%I"
    )
)
endlocal

单命令行版本:

@for /F "delims=." %%I in ('dir "D:\backup\????????.*" /AD /B /ON 2^>nul') do @for /F "skip=2 delims=" %%D in ('dir "D:\backup\%%I.*" /AD /B /O-D-N /TC') do @dir "D:\backup\%%D" /A-D /B /ON /S >>"D:\backup\DeletedFiles.log" 2>nul & rd /Q /S "D:\backup\%%D"