【问题标题】:Windows batch to keep the newest N files based on the timestamp in filenameWindows批处理根据文件名中的时间戳保留最新的N个文件
【发布时间】:2019-02-12 19:58:23
【问题描述】:

我需要一个批处理脚本来根据文件名中的时间戳仅保留最新的 N 个文件,并且仅当大小大于 150 KB 时(如果大小较小,则意味着备份的文件已损坏并且可以删除) . 我发现了类似的脚本,但仅适用于 Linux。

脚本应首先删除所有小于 150 KB 的文件,并使用文件名中的时间戳而不是文件的修改日期作为参考,保留最新的 N 个文件。

除了周末,这个 .txt 文件每天都会修改几次。 该文件每天备份几次,并在文件名中添加日期和时间。

文件名示例:Test_2019-01-16_21-57-34.txt

路径是:Z:\
操作系统是Windows 8

【问题讨论】:

  • 将您的任务分解为逻辑步骤,然后根据网站/站点搜索,以及在命令提示符后跟/? 输入时使用的每个命令的输出,逐步尝试每个步骤跨度>
  • @Compo:我找到了如何删除大小小于自定义大小的文件。但我不知道如何过滤文件名中带有时间戳的文件。
  • 您的时间戳是可排序的,所以如果文件都具有前缀 Test_for /f "delims=" %%A in ('Dir /B /O-N Test_*.txt') do (..) 并检查/计算带有 IF 的文件应该可以。

标签: batch-file timestamp filenames


【解决方案1】:

此任务可以使用以下批处理文件完成:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
pushd "Z:\" || goto :EOF
for /F "eol=| delims=" %%I in ('dir /A-D-H /B /OS "Test_*.txt" 2^>nul') do if %%~zI LEQ 153600 (del "%%I") else goto DeleteOldFiles
:DeleteOldFiles
for /F "skip=5 eol=| delims=" %%I in ('dir /A-D-H /B /O-N "Test_*.txt" 2^>nul') do del "%%I"
popd
endlocal

使用命令 PUSHD 将目录 Z:\ 设置为当前目录,退出批处理文件执行,goto :EOF 失败。

下一个命令FOR在命令行后台的单独命令进程中使用cmd.exe /c(更准确地说是%ComSpec% /c)执行:

dir /A-D-H /B /OS "Test_*.txt" 2>nul

命令DIR输出

  • 非隐藏文件的名称,因为选项/A-D-H(属性不是目录且未隐藏)
  • 由于选项/B,在没有任何附加数据的裸格式中
  • 由于选项/OS,按大小排序,最小文件在前,最大文件在后
  • 匹配当前目录中的通配符模式Test_*.txt

通过将错误消息从句柄 STDERR 重定向到设备 来抑制 DIR 在当前目录中找不到任何符合这些条件的目录条目时输出的错误消息NUL

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

FOR 捕获为处理已启动命令进程的 STDOUT 而编写的所有内容,并在启动 cmd.exe 自行终止后逐行处理捕获的输出。

带有选项 /F

FOR 会忽略在使用带有选项 /BDIR 时不会出现的空行。

FOR 将使用普通空格和水平制表符作为分隔符将每一行拆分为子字符串(标记),并将仅将第一个空格/制表符分隔的字符串分配给指定的循环变量I。通过使用 delims= 定义字符串分隔符的空列表来禁用此行拆分行为。在这种情况下,delims= 并不需要,因为备份文件的文件名不包含空格字符。

FOR 还将忽略将行拆分为子字符串后的第一个子字符串(不一定是分配给循环变量的子字符串)以分号开头的行,因为 ; 是默认值行尾字符。文件名可以以分号开头,因此最好将带有eol=|eol=? 的行尾字符重新定义为文件名不能包含的竖线或问号。在这种情况下,eol=| 不是必需的,因为 DIR 的输出只是以Test_ 开头的文件名,因此默认的eol=; 不需要用eol=| 覆盖。

IF 命令将当前文件的 size 与值 153600 进行比较,即 150 KiB,如果文件的大小小于或等于该值,则文件被删除.

注意: Windows 命令处理器使用带符号的 32 位算法。因此,此 IF 条件无法正确处理超过 2,147,483,647 字节 (2 GiB) 的文件。如果备份文件可以大于 2 GiB,则有必要解决这个带符号的 32 位算术限制。

否则第一个循环将退出,并在当前文件大于 150 KiB 时跳转到标签 DeleteOldFiles 下方的行,因为该文件和该文件之后由 DIR 输出的所有其他文件都有一个文件大小大于 150 KiB。

第二个 FOR 循环在后台的单独命令进程中再次运行命令 DIR。但是 DIR 选项/OS/O-N 替换,以根据文件名以相反的顺序获取文件名输出。 DIR首先输出日期最新的文件名,文件名中日期最旧的文件名最后输出。

第二个FOR 命令行另外包含选项skip=5 以跳过前五个 文件名,即最新的五个 备份文件。

如果DIR 输出超过五个 的文件名,所有其他早于前五个 输出文件名的文件将被命令DEL 由第二个 FOR 无条件执行。

最后使用POPD将初始当前目录再次设置为当前目录。

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

  • del /?
  • dir /?
  • echo /?
  • for /?
  • goto /?
  • if /?
  • popd /?
  • pushd /?

另见:

还有一个提示:如果将驱动器号 Z: 分配给网络资源,则将 Z:\ 替换为 UNC 路径。并确保批处理文件由有权访问网络资源并删除网络资源上该文件夹中的文件的帐户执行,以防该批处理文件作为计划任务执行。另见What must be taken into account on executing a batch file as scheduled task?

【讨论】:

  • 这是对任何关于 SO 问题的深思熟虑的答案之一。谢谢你真棒。
猜你喜欢
  • 1970-01-01
  • 2012-06-17
  • 1970-01-01
  • 1970-01-01
  • 2013-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-17
相关资源
最近更新 更多