且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-09-26 09:04:34

此任务的批处理文件为:

A batch file for this task would be:

@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 ,以便以后逐行处理它.

The first, outer FOR executes in a separate command process started with cmd /c in background the DIR command line specified in first parenthesis and captures everything output by DIR to handle STDOUT for processing it later line by line.

使用的 DIR 命令输出

  • 仅由于/AD(属性目录)而与通配符模式????????.*相匹配的目录
  • 由于/B(裸格式),其名称仅带有路径而没有路径
  • 由于/ON而按名称排序(按名称排序).
  • only directories matching wildcard pattern ????????.* because of /AD (attribute directory)
  • with only their names without path because of /B (bare format)
  • sorted by name because of /ON (ordered by name).

当前备份文件夹中可能不包含与此模式匹配的文件夹.在这种情况下, DIR 将输出一条错误消息以处理 STDERR ,由于包含 file 而不是目录,这会造成混乱>.该可能的错误消息被重定向到设备 NUL 进行抑制.

It is possible that the backup folder currently contains no folder matching this pattern. In this case DIR would output an error message to handle STDERR which would be confusing because of containing file instead of directory. This possible error message is redirected to device NUL to suppress it.

阅读有关使用命令重定向操作符的Microsoft文章, 2>nul的说明.当Windows命令解释器在执行命令 FOR 之前处理此命令行时,重定向操作符>必须在 FOR 命令行上转义字符^进行转义,以将其解释为文字字符. >在后台启动的单独命令过程中执行 DIR 命令行.

Read the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the DIR command line in a separate command process started in background.

外部 FOR 处理捕获的行,而忽略空行和以分号开头的行.这样的行在这里不存在,所以没有问题.每行(其他)都使用.作为分隔符分成两个字符串.仅将每行第一行.左边的第一个字符串分配给循环变量I,该变量在接下来执行的命令行中使用.

Outer FOR processes the captured lines with ignoring empty lines and lines starting with a semicolon. Such lines do not exist here, so no problem. Each (other) line is split up into two strings using . as delimiter. Only the first string left to first . of each line is assigned to loop variable I which is used in the command lines executed next.

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

It is important here to use command DIR to get a directory list processed by FOR not being modified during loop execution instead of using for /D which would read next directory name directly from file system on each iteration of the loop. The list of directories changes during loop execution. On using for /D it could happen that some directories are skipped because of directory list changes while processing the directories.

IF 条件使用延迟的环境变量扩展进行简单的区分大小写的字符串比较,以将先前处理的文件夹的日期字符串与当前文件夹进行比较.仅在最后处理的文件夹的日期与当前文件夹的日期之间的差值执行内部循环.这种 IF 条件只是为了使文件夹删除过程更快一些.

The IF condition makes a simple case-sensitive string comparison using delayed environment variable expansion to compare the date string of previous processed folder(s) with the current folder. Only on difference between date of last processed folder(s) and date of current folder the inner loop is executed. This IF condition is just for making the folder deletion process a little bit faster.

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

It is no problem here to use delayed environment environment variable expansion as no folder in backup folder contains an exclamation mark in folder name.

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

The second, inner FOR loop runs also command DIR to get a list of directories with the date string of current folder with just their names, but this time first reverse ordered by creation date and second reverse ordered by name in case of two or more folders have same creation date because of /O-D-N (ordered reverse by date and next reverse by name) and /TC (time: creation). Reverse date order means newest directory is output first and oldest is output last.

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

The inner FOR loop processes the captured lines output by DIR with skipping the first two lines which means ignoring the two newest folders. The other lines are processed without splitting the line up because of delims= (empty delimiter list) and therefore the complete folder name as output by DIR is assigned to loop variable D.

由于/Q,命令 RD 会自动删除名称保留在循环变量D中的文件夹,由于/S,所有文件和子文件夹都将被删除.

The command RD deletes the folder of which name is hold in loop variable D quietly because of /Q with all files and subfolders because of /S.

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

Then the date string of current folder is assigned to environment variable LastDate to skip all folders in directory list of outer FOR with same date string.

在不使用延迟的环境变量扩展的情况下也可以使用单个命令行的速度稍慢一些,这对于名称为!的文件夹也适用.

It would be also possible to use a single command line without usage of delayed environment variable expansion being a bit slower which would also work for folders with ! in name.

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

要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面.

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

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

更新:

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

Enhanced version logging the names of all files with full path before deletion of a backup directory.

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