仅当存在较新的文件时才删除文件的 Bat 文件

2024-05-10

我们的备份系统每天都会创建 .bak 文件,如果遇到问题,我们可以使用该文件来恢复文件。如果不管这些,它们会填满我们的存储空间,所以我找到了一个批处理文件,我可以在创建新批处理文件后每天运行该文件来删除旧的批处理文件。

forfiles -p "c:\xxx\yyy" -s -m *.bak /D -2 /C "cmd /c del @path"

这工作正常,但我想创建一个安全网,这样如果由于某种原因我们的备份系统失败并且没有创建新的 .bak 文件,旧的 .bak 文件将保留在那里而不是被删除,否则我们将留下发生事故时没有备份文件。因此,理想情况下,我想要一些能够检查不到一天的 .bak 文件的工具,如果这些文件不存在,则不会运行上面的行,但如果存在这些较年轻的文件,它将运行上面的行并删除较旧的文件。不确定这是否可以通过批处理文件实现。预先感谢您对此的帮助。

编辑:关于我需要的更多信息。每天晚上10点左右备份50个左右.bak文件被创建并放入文件夹 c:\xxx\yyy 这些文件非常大,因此我设置了一个批处理文件每天自动运行,删除所有文件.bak超过 1 天的文件。这对于日常使用来说很好,但我脑海中的场景是如果备份系统没有创建.bak无论出于何种原因的文件。我想要检查批处理文件以确保新的.bak文件在删除旧文件之前已创建。基本上,使用批处理文件有一种方法可以检查文件夹中是否存在比 1 天更新的特定文件类型,并且我们可以根据结果更改批处理文件的功能。

这些是 18 日和 19 日创建的文件示例。

2004 Apr_backup_2017_12_18_210001_2986007.bak
2004 Apr_backup_2017_12_19_210001_3168635.bak
Subscribers_backup_2017_12_19_210003_3012893.bak
model_backup_2017_12_19_210003_2544131.bak

它们似乎都遵循以下格式:

[DESC]_backup_[YEAR]_[MONTH]_[DAY]_21000[1/2/3]_[7 DIGIT NO.].bak

我认为,一份未知的名单[DESC]所有备份文件名中的字符串在批处理文件中最难处理。代码可以非常简单地了解这个列表,如下所示,或者至少了解这些字符串是否不包含对批处理文件处理至关重要的字符,例如!%=.

但是未知列表的编码挑战[DESCR]文件名中带有特殊字符的字符串对我来说很有趣,因此我首先开发了以下注释批处理文件:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "BackupFolder=C:\xxx\yyy"

rem Search for files matching the wildcard pattern *_backup_*.bak in backup
rem folder, assign each file name without file extension to environment
rem variable FileName and call the subroutine GetUniqueDescs to get the
rem file description at beginning of each file name into a list in memory.

for /F "delims=" %%I in ('dir "%BackupFolder%\*_backup_*.bak" /A-D /B /ON 2^>nul') do (
    set "FileName=%%~nI"
    call :GetUniqueDescs
)

rem Run command SET with FileDesc: to output all environment variables
rem starting with that string in name and sorted by name and process
rem this list whereby each line ends with =1 as value 1 is assigned
rem to each of these environment variables.

rem For each unique file description in output list assign the file
rem description with =1 appended to environment variable FileDesc
rem and run subroutine DeleteFiles.

for /F "tokens=2 delims=:" %%I in ('set FileDesc: 2^>nul') do (
    set "FileDesc=%%I"
    call :DeleteFiles
)

rem Restore initial environment on starting this batch file and exit it.
endlocal
goto :EOF


rem The subroutine GetUniqueDescs first runs a string substitution which
rem gets the backup pattern part from file name, i.e. everything in file
rem name from _backup_ to end of file name.

rem Then another string substitution is used to remove this string from
rem current file name to get just the description and define an environment
rem variable of which name starts with FileDesc: and ends with the file
rem description. The value assigned to this environment variable is 1.

:GetUniqueDescs
set "BackupPart=%FileName:*_backup_=_backup_%"
call set "FileDesc:%%FileName:%BackupPart%=%%=1"
goto :EOF


rem The subroutine DeleteFiles removes first from passed file description
rem the last two characters being always =1 from list of environment
rem variables starting with FileDesc: and appends the backup wildcard
rem pattern.

rem Command DIR is used to find all files in backup folder starting
rem with current file description and _backup_ and output the found
rem files sorted by last modification date with newest modified file
rem first and oldest modified file last.

rem The command FOR processing this list skips the first file name
rem output by DIR which means the newest file. All other, older
rem files perhaps also found by DIR are deleted one after the other.

:DeleteFiles
set "FilePattern=%FileDesc:~0,-2%_backup_*.bak"
for /F "skip=1 delims=" %%J in ('dir "%BackupFolder%\%FilePattern%" /A-D /B /O-D /TW') do ECHO del "%BackupFolder%\%%J"
goto :EOF

命令ECHO在命令之前的最后一行del结果只是显示哪些文件将被删除,而不是真正删除它们。

选项skip=1最后一行确定始终保留多少个备份文件。

例如使用skip=5结果是根据备份文件上的最后修改日期(通常也是创建日期)保留最新的五个文件,并删除所有其他文件。

这样的备份删除策略的优点是无所谓:

  1. 创建特定备份的频率 - 每天、每周或每月;
  2. 上次备份创建是否成功;
  3. 是否手动删除了部分甚至全部备份文件;
  4. 每个单独的备份文件有多旧;
  5. 执行删除备份文件的批处理文件的频率。

删除备份真正重要的是每个备份所需的存储大小以及删除过程后剩余多少可用存储空间。备份文件的文件日期不限制可用存储大小。所有剩余备份文件的文件大小和备份介质上的总存储大小是真正重要的因素。这就是为什么我不明白所有这些“删除早于”的问题。只要有足够的可用空间容纳新文件,谁还需要关心文件的年龄?

文件创建日期也可以通过使用/TC代替/TW在最后一行。但文件创建日期是在该目录中创建文件的日期,而不是文件本身的创建日期。因此,文件创建日期仅当文件自第一次创建以来从未被复制或移动到另一个目录时才有用。

我在以下文件上测试了这个批处理文件:

C:\xxx\yyy\2004 !Apr_backup_2017_12_18_210001_2986007.bak
C:\xxx\yyy\2004 !Apr_backup_2017_12_19_210001_3168635.bak
C:\xxx\yyy\model%_backup_2017_12_19_210003_2544131.bak
C:\xxx\yyy\model%_backup_2017_12_20_210003_2544131.bak
C:\xxx\yyy\Subscribers=_backup_2017_12_19_210003_3012893.bak
C:\xxx\yyy\Subscribers=_backup_2017_12_20_210003_3012893.bak

每个文件的最后修改日期与文件名中的日期匹配。

批处理文件的输出是:

del "C:\xxx\yyy\2004 !Apr_backup_2017_12_18_210001_2986007.bak"
del "C:\xxx\yyy\model%_backup_2017_12_19_210003_2544131.bak"
del "C:\xxx\yyy\Subscribers=_backup_2017_12_19_210003_3012893.bak"

这就是预期的结果。每个文件对中较旧的文件将被删除。


然后我想得到[DESC]文件名的一部分可以更容易完成,因为不带文件扩展名的文件名的其余部分的固定长度为 33 个字符。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "BackupFolder=C:\xxx\yyy"

rem Search for files matching the long wildcard pattern
rem *_backup_????_??_??_??????_???????.bak
rem in backup folder and assign each file name without
rem file extension to environment variable.

rem The last 33 characters are removed from each file name to get the
rem file description part at beginning of each file name. Then define
rem an environment variable of which name starts with FileDesc: and
rem ends with the file description. The value assigned to this
rem environment variable is 1.

for /F "delims=" %%I in ('dir "%BackupFolder%\*_backup_????_??_??_??????_???????.bak" /A-D /B /ON 2^>nul') do (
    set "FileName=%%~nI"
    call set "FileDesc:%%FileName:~0,-33%%=1"
)

rem Run command SET with FileDesc: to output all environment variables
rem starting with that string in name and sorted by name and process
rem this list whereby each line ends with =1 as value 1 is assigned
rem to each of these environment variables.

rem For each unique file description in output list assign the file
rem description with =1 appended to environment variable FileDesc
rem and run subroutine DeleteFiles.

for /F "tokens=2 delims=:" %%I in ('set FileDesc: 2^>nul') do (
    set "FileDesc=%%I"
    call :DeleteFiles
)

rem Restore initial environment on starting this batch file and exit it.
endlocal
goto :EOF


rem The subroutine DeleteFiles removes first from passed file description
rem the last two characters being always =1 from list of environment
rem variables starting with FileDesc: and appends the backup wildcard
rem pattern.

rem Command DIR is used to find all files in backup folder starting
rem with current file description and _backup_ and output the found
rem files sorted by last modification date with newest modified file
rem first and oldest modified file last.

rem The command FOR processing this list skips the first file name
rem output by DIR which means the newest file. All other, older
rem files perhaps also found by DIR are deleted one after the other.

:DeleteFiles
set "FilePattern=%FileDesc:~0,-2%_backup_*.bak"
for /F "skip=1 delims=" %%J in ('dir "%BackupFolder%\%FilePattern%" /A-D /B /O-D /TW') do ECHO del "%BackupFolder%\%%J"
goto :EOF

该批处理文件还包含ECHO留给指挥del最后一行对备份文件夹中的六个文件产生相同的结果。

我不知道批处理文件是否可以在不知道其中可能存在哪些字符的情况下进一步优化[DESC]文件名的一部分。我没有考虑可能的进一步优化。


让我们假设唯一的列表[DESC]字符串是众所周知的,可以在批处理文件中进行硬编码,例如2004 !Apr, model% and Subscribers=对于我的测试用例中的六个文件:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "BackupFolder=C:\xxx\yyy"
for %%I in ("2004 !Apr" "model%%" "Subscribers=") do for /F "skip=1 delims=" %%J in ('dir "%BackupFolder%\%%~I*_backup_*.bak" /A-D /B /O-D /TW 2^>nul') do del "%BackupFolder%\%%J"
endlocal

这个批处理文件确实删除了文件,因为没有ECHO在最后一行。

哦,是的,知道各个备份文件名会让一切变得更加容易。

批处理文件甚至可以优化为单个命令行:

@for %%I in ("2004 !Apr" "model%%" "Subscribers=") do @for /F "skip=1 delims=" %%J in ('dir "C:\xxx\yyy\%%~I*_backup_*.bak" /A-D /B /O-D /TW 2^>nul') do @del "C:\xxx\yyy\%%J"

最佳和简单的备份删除概念

在备份存储介质上创建:

  1. 带有文件名的整个机器的备份ComputerName_backup_YYYY_MM.tib每三个月一次,占用 200 GiB 的空间,并且备份存储介质上只需要最后一次备份就足够了;
  2. 包含不经常更新文件名的文件的文件夹的备份Folder_backup_YYYY_MM_DD.zip每周六,存储介质上大约需要 400 MiB,足以恢复过去四个星期;
  3. 带有文件名的数据库文件的备份Database_backup_YYYY_MM_DD.bak每天,目前每个备份需要 20 MiB,但与数据库文件的典型情况一样,其增长或多或少会持续增长,并且应该可以恢复过去 7 天的数据条目。

所需的最小存储介质大小为:

(1+1) × 200 GiB + (4+1) × 400 MiB + (7+1) × (20×3) MiB

1 TiB 的存储介质大小实际上足以满足大约未来三年的需求,具体取决于数据库备份的增长速度(计算中已包含三倍的增长)。

最好删除创建每日数据库备份时不再需要的所有备份文件,以通过使用单个简单的批处理文件来保持备份文件管理的简单性。

@echo off
set "BackupFolder=C:\xxx\yyy"
call :DeleteBackups 1 "ComputerName"
call :DeleteBackups 4 "Folder"
call :DeleteBackups 7 "Database"
goto :EOF

:DeleteBackups
for /F "skip=%1 delims=" %%I in ('dir "%BackupFolder%\%~2*_backup_*" /A-D /B /O-D /TW 2^>nul') do del "%BackupFolder%\%%I"
goto :EOF

只要考虑正确的策略,删除不再需要的备份就可以非常容易。


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

  • call /?
  • del /?
  • dir /?
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • rem /?
  • set /?
  • setlocal /?

另请阅读 Microsoft 的文章:使用命令重定向运算符 https://technet.microsoft.com/en-us/library/bb490982.aspx的解释2>nul。重定向运算符>必须用插入符号转义^ on FOR当 Windows 命令解释器在执行命令之前处理此命令行时,命令行将被解释为文字字符FOR它执行嵌入的dir命令行使用在后台启动的单独命令进程。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

仅当存在较新的文件时才删除文件的 Bat 文件 的相关文章

  • 在重定向文件 (>output.txt) 中显示带重音符号的字符

    example mode con cp gt tmp output tmp notepad tmp output tmp show Statut du p riph rique CON Page de codes 850 代替 Statut
  • 如何运行 Windows 批处理文件但隐藏命令窗口?

    如何运行 Windows 批处理文件但隐藏命令窗口 我不希望 cmd exe 在执行文件时在屏幕上可见 这可能吗 如果你写一个非托管程序并使用创建进程 https learn microsoft com en us windows win3
  • 在 C# 中编写批处理脚本的好方法是什么?

    我想用 C 编写简单的脚本 我通常会使用 bat 或 4NT btm 文件 复制文件 解析文本 询问用户输入等等 相当简单 但在批处理文件中正确执行这些操作确实很困难 例如没有例外 我熟悉像 AxScript 这样的命令行 脚本 包装器 这
  • 批量检测系统是32位还是64位

    有谁知道如何创建一个批处理文件 如果是 64 位系统 可以对一个程序进行 shell 处理 如果是 32 位系统 则可以对另一个程序进行 shell 处理 检查 PROCESSOR ARCHITECTURE being x86 if PRO
  • 如何在Windows 7中使用批处理脚本获取本地连接名称

    我正在编写一个简单的批处理脚本来检索 Windows 上的所有网络接口 但我只需要本地连接名称 本地连接接口名称不是默认名称 有没有办法使用批处理脚本仅检索本地连接名称作为字符串 不完全确定您在问什么 但我认为您的问题是您想要获取网络接口的
  • 如何查找具有特定模式的文件夹和文件

    我想编写一个批处理文件 该文件将写入日志包含特定模式以及排除文件夹的所有文件和文件夹 但没有成功 ECHO OFF for r c x in david do echo x findstr f exclude txt c x gt nul
  • 在进程完成之前,Windows cmd.exe 中的管道不会转发标准输出?

    考虑 Windows 命令 shell cmd exe 中的管道 C gt feed filter 直到进料过程运行完成之后 进料过程的标准输出似乎才达到过滤过程的标准输入 这种类型的 缓冲 可能会导致长时间运行的馈送过程的输出消息出现烦人
  • 批处理 - IF ELSE 启动功能的条件无论如何都会执行

    提前抱歉 如果这里有一个线程可以回答我的问题 我从周五开始就一直在这个问题上并四处寻找 我确实发现了一些类似的问题 但我无法应用或适应这个问题 据我所知 简而言之 我有一个批处理脚本 它创建目录的文本文件 然后该脚本在目录中搜索文件 如果文
  • DOS批处理文件for循环中的变量赋值问题

    我在 DOS 脚本 for 循环中遇到变量赋值问题 它从不分配值 它总是空白 下面是示例代码 echo off set ans 1 SET STRING ans echo Parsing the string STRING for f to
  • 包含带空格的可执行路径的环境变量是否也应包含必要的引号?

    定义环境变量时 对我来说 在 Windows 上 也许有一个更通用的准则 set MY TOOL C DevTools bin mytool exe 如果该工具位于带有空格的路径上 set MY TOOL C Program Files x
  • 从目录获取第一个文件名的批处理脚本

    我的函数需要特定目录中的第一个文件名来使用第一个文件处理一些测试 完成测试后从目录中删除第一个文件 我尝试如下 FOR R
  • 忽略批处理文件中的百分号

    我有一个批处理文件 可将文件从一个文件夹移动到另一个文件夹 批处理文件是由另一个进程生成的 我需要移动的一些文件中包含字符串 20 move y myserver myfolder file 20name txt myserver othe
  • 最后一个参数中的正斜杠会导致批处理文件目录(“%~dp0”)的路径发生更改

    我正在学习如何在批处理脚本中使用参数 并最终创建了某种用于读取参数和设置参数的模板 echo off SetLocal EnableDelayedExpansion set needextra set errstat set noflag
  • 如何通过 DOS 批处理命令发送电子邮件?

    我在 DOS 中有一个批处理文件 可以进行一些检查 完成后我需要发送一封电子邮件 我在 interwebz 上找到了一些解决方案 但大多数都是第三方的 或者只是在 Outlook 中打开新邮件 我需要命令来发送完整的电子邮件 而无需任何人工
  • 2 批字符串问题

    1 是否有任何内置函数可以告诉我变量的内容是否仅包含大写字母 2 有没有办法查看变量是否包含字符串 例如 我想查看变量 PATH 是否包含 Ruby 对于第 1 部分 findstr就是答案 您只需使用正则表达式功能即可errorlevel
  • 用于列出文件夹但排除特定文件夹的批处理脚本

    我希望此脚本列出文件夹名称中包含 deleted 的所有文件夹 但如果它们位于名为 done 的文件夹中则不列出 例如 列出文件夹 如果位于 C temp如果它在C temp random folder name但如果它在C temp do
  • 获取给定卷的驱动器号?

    给定硬盘卷名 如何在 Windows 7 中使用批处理文件获取驱动器号 Using 电源外壳 questions tagged powershell Get WMIObject Win32 logicaldisk where volumen
  • Grep 批量 ping

    寻找一种更好的方法来做到这一点 而不是我习惯的 手动 方法 因为这是一个我必须定期经历的过程 我有一系列要 ping 的 IP 从10 0 1 15 to 10 0 50 15 第三个八位位组指的是物理位置 最后一个八位位组指的是该位置处的
  • 为什么 Windows 命令 DIR 在搜索 *.tif 文件时也会输出 *.tiff 文件?

    我想使用 Windows 命令DIR为了找到唯一TIF文件 即具有扩展名的文件 tif 因此我使用以下小批处理文件 for f delims a IN dir b a d s C wolter testversion input tif d
  • 通过批处理文件自动化 cygwin

    长话短说 我们有多个服务器 我们每晚都在其上运行 perflog 监控 我的工作是将这些日志转换为 csv 格式并将它们发送到我的电子邮件 这一点已经通过前员工编写的 sh 脚本实现了自动化 我想要自动化的是在 perfmon 日志记录之后

随机推荐

  • 使用 JSONPath 解析 JSON 属性内的 JSON

    我有一个 JSON 列表 其中每个元素的属性之一恰好是 JSON 本身 它来自于糟糕的前期设计 但事实就是如此 我想查询元素中包含的 JSON 字符串内的不同属性 这是一个例子 只有一项 我手写了代码 但相信我 通过生成它的方式 它在生产中
  • 如何从 Laravel 将路由参数传递到 Vue.js

    我有这样的路线来获取带有相关评论的帖子 Route get api topics category id title function category id title return App Topic with comments gt
  • 检测 iPad Safari 用户的最佳方法

    添加用于检测 iPad Safari 用户的代码的最佳方法是什么 我的意思是我们应该使用 1 CSS 通过链接媒体 2 JS 通过navigator对象 我听说使用用户代理字符串并不是检测 iPad 的最佳方法 因为存在不一致的情况 请建议
  • 我有一个 Employee 类,我想返回“姓名”列表

    我有一个 Employee 类 我想返回 姓名 列表 雇员 py class Employee object def init self id name members None self id id self name name self
  • Liferay ajax 请求和 JSON 响应

    我是 Liferay 的新人 我使用服务生成器来创建数据库 我手动填充它们 最终我可以使用 JSP 调用它们PersonLocalServiceUtil class 现在我想在我的程序中使用Ajax 例如 有属性的人personID per
  • 在分布式事务中手动登记后,使用 enlist=false 的连接不会关闭

    我有一个分布式事务上下文使用ServiceDomain 在其中 我打开一个 SQL 连接 其中连接字符串指定Enlist false 这样它就不是自动地被纳入交易 然后 如果我使用手动在分布式事务中登记连接EnlistDistributed
  • Twitter bootstrap 远程模式每次都显示相同的内容

    我正在使用 Twitter bootstrap 我已经指定了一个模式 div class modal hide div class modal header div div
  • 快速 log2(float x) 实现 C++

    我需要在 C 中非常快速地实现 log2 float x 函数 我发现了一个非常有趣的实现 而且速度非常快 include
  • DMARC/SPF/DKIM 未使用第三方邮件进行身份验证

    我们最近为我们的域实施了 DMARC 记录 v DMARC1 p 隔离 pct 100 rua mailto 电子邮件受保护 cdn cgi l email protection 隔离 100 未经身份验证的电子邮件并将汇总报告发送给 我
  • 如何使用 Java 原生接口从 Java 调用 Go 函数?

    可以通过以下方式调用 C 方法JNA https en wikipedia org wiki Java Native AccessJava 中的接口 如何使用 Go 实现相同的功能 package main import fmt impor
  • Xamarin 测试记录器选项有错误。无法记录自动化测试

    选项 gt Xamarin gt Xamarin Test Recorder 中的所有设置都有错误 我的桌面上安装了 Visual Studio 2015 企业版 以及 Xamarin 和 Xamarin Test Recorder 插件
  • 等待程序完成

    为了监视带宽使用情况并且不要在启动时加载不必要的程序 我想先执行dumeter exe 然后执行firefox exe 当我关闭firefox时 它应该杀死dumeter 我使用以下代码启动 Set WshShell WScript Cre
  • 是否可以向 JavaScript 函数发送可变数量的参数?

    是否可以从数组向 JavaScript 函数发送可变数量的参数 var arr a b c var func function debug alert arguments length for arg in arguments alert
  • 在 Mac 上使用 JRE 打开 jar 文件

    我有一个 jar 文件 旨在通过命令行运行 我不打算在运行应用程序的机器上进行任何java开发 我的思考过程是 因此我应该只需要JRE而不是JDK 此外 JDK 大约是 JRE 的 4 倍 我不想下载它 在 Mac 上安装 JRE 时 它不
  • grails 上的同步块在 Windows 上有效,但在 Linux 上无效

    我有一个 grails 应用程序 它依赖于服务中的同步块 当我在 Windows 上运行它时 同步按预期工作 但当我在 ams linux 上运行时 会出现 StaleObjectStateException 该问题在以下示例中重现 cla
  • Phonegap fileTransfer 上传不 POST 参数

    希望有人能帮助我 我正在为 iOS 和 Android 开发一个 Phonegap 应用程序 它使用 Cordova fileTransfer 对象的上传方法 我正在上传音频文件 参数设置如下 var params params Dicti
  • 以编程方式将列名称添加到 numpy ndarray

    我正在尝试将列名称添加到 numpy ndarray 然后按名称选择列 但这不起作用 我无法判断问题是在添加名称时出现 还是在稍后尝试调用它们时出现 这是我的代码 data np genfromtxt csv file delimiter
  • PHP使用正则表达式查找字符串

    我已经阅读了多个有关正则表达式的教程 但它只是不会留在我的脑海中 我永远无法让我的模式发挥作用 希望有人能帮忙 我有一个 php 变量 content 我需要在其中找到如下所示的特定模式 图库 名称 文件夹 我想搜索 starting wi
  • 在 Typescript 中从基类创建子类的新实例[重复]

    这个问题在这里已经有答案了 我想创建新实例Child班级来自Base类方法 这有点复杂 但我会尽力解释 这是一个例子 class Base constructor clone Here i want to create new instan
  • 仅当存在较新的文件时才删除文件的 Bat 文件

    我们的备份系统每天都会创建 bak 文件 如果遇到问题 我们可以使用该文件来恢复文件 如果不管这些 它们会填满我们的存储空间 所以我找到了一个批处理文件 我可以在创建新批处理文件后每天运行该文件来删除旧的批处理文件 forfiles p c