Bat文件仅在存在较新的文件时才删除文件 [英] Bat file to delete files only when younger files are present

查看:90
本文介绍了Bat文件仅在存在较新的文件时才删除文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们的备份系统每天都会创建.bak文件,如果遇到问题,我们可以使用它们来还原文件.如果不加处理,这些文件将占满我们的存储空间,因此我找到了一个批处理文件,可以在创建新的批处理文件后每天删除该批处理文件.

Our backup system creates .bak files everyday which we can use to restore files if we ever run into issues. If left alone these would fill up our storage so I found a batch file that I can run to delete the old batch files everyday after new ones are created.

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

这工作正常,但我想创建一个安全网,以便无论出于何种原因我们的备份系统出现故障并且未创建新的.bak文件,旧的.bak文件都将保留在那里而不是被删除,否则我们将发生事件时,不保留任何备份文件.因此,理想情况下,我想要一种可以检查小于一天的.bak文件的文件,如果不存在这些文件,则不会运行上述行,但是如果存在那些较年轻的文件,它将运行上述行并删除较旧的文件.不知道是否可以使用批处理文件.在此先感谢您的帮助.

This works fine but I want to create a safety net so that if for whatever reason our backup system fails and the new .bak files aren't created the old .bak files will stay there instead of being deleted, otherwise we would be left with no backup files in the event of an incident. So ideally I want something that will check for .bak files younger than one day and if those files are not present it won't run the above line but if those younger files are present it will run the above line and delete the older files. Not sure if this is possible with batch files or not. Thanks in advance for your help on this.

有关我需要的更多信息.每天晚上10点左右,将创建约50个备份.bak文件并将其放入文件夹c:\ xxx \ yyy 这些文件非常大,因此我设置了一个批处理文件以每天自动运行,以删除所有早于1天的.bak文件.这对于日常使用来说是很好的选择,但是我脑海中的情况是,如果备份系统出于任何原因没有创建.bak文件,该怎么办.我希望批处理文件检查以确保在删除旧文件之前已创建新的.bak文件.基本上使用批处理文件,可以检查文件夹中是否存在比1天新的文件类型,我们可以根据结果更改批处理文件的功能.

Some more info on what I need. Everyday at around 10pm around 50 backup .bak files are created and put into folder c:\xxx\yyy These files are quite large so I have set up a batch file to run automatically every day that removes all .bak files that are older than 1 day. This is fine for everyday use but the scenario I have in my head is what if the backup system doesnt create the .bak files for whatever reason. I want the batch file to check to make sure the new .bak files have been created before it deletes the old ones. Basically using a batch file is there a way to check if there is a certain file type in a folder that is newer than 1 day old and can we change what the batch file does depending on the outcome.

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

These are examples of the files created for the 18th and 19th.

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

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

They all seem to follow the below format:

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

推荐答案

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

I think, an unknown list of [DESC] strings in all the backup file names is most difficult to handle in batch file. The code could be very simple on knowing this list as it can be seen below, or at least on knowing if those strings do not contain characters being critical on batch file processing like !%=.

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

But the coding challenge for unknown list of [DESCR] strings with special characters in file names was interesting for me and so I developed first following commented batch file:

@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之前一行导致只显示要删除的文件,而不是真正删除它们.

The command ECHO in last but one line before command del results in just getting displayed which files would be deleted instead of really deleting them.

最后一个选项skip=1但只有一行决定了始终保留多少备份文件.

The option skip=1 in last but one line determines how many backup files are always kept.

例如,使用skip=5会导致根据上次修改日期将最新的5个文件保留在备份文件中,同时还将保留创建日期并删除所有其他文件.

For example using skip=5 results in keeping the newest 5 files according to last modification date being usually on backup files also the creation date and deleting all others.

这种备份删除策略的优点在于它无关紧要:

The advantage of such a backup deletion strategy is that it does not matter:

  1. 特定备份的创建频率-每天,每周或每月;
  2. 如果上一次备份创建完全成功;
  3. 如果手动删除了部分甚至所有备份文件;
  4. 每个备份文件的年龄;
  5. 删除备份文件的批处理文件执行的频率.

删除备份真正重要的是每个备份所需的存储大小以及删除过程后剩余多少可用存储空间.备份文件的文件日期不限制可用存储空间.其余所有备份文件的文件大小以及备份介质上的总存储大小才是真正重要的因素.这就是为什么我不理解所有那些删除时间早于"的问题的原因.只要有足够的可用空间来存储新文件,谁会关心文件的使用期限?

What really matters on deletion of backups is the storage size needed for each backup and how much free storage space remains after deletion process. The file date of a backup file is not limiting the free storage size. The file sizes of all remaining backup files and the total storage size on backup media are the factors which really matter. That's why I do not understand all those "delete older than" questions. Who has to care about age of a file as long as there is enough free space for new files?

文件创建日期也可以通过在最后一行中使用/TC而不是/TW来使用.但是文件创建日期是在该目录中创建文件的日期,而不是文件本身的创建日期.因此,文件创建日期仅在自首次创建以来从未将文件复制或移动到其他目录时有用.

The file creation date could be also used by using /TC instead of /TW in last but one line. But the file creation date is the date on which the file was created in that directory and not on which the file itself was created. For that reason the file creation date is only useful when the file was never copied or moved to another directory since first time creation.

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

I tested this batch file on following files:

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

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

The last modification date of each file matched the date in file name.

批处理文件的输出为:

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"

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

That is the expected result. The older file of each file pair would be deleted.

然后,我认为获取文件名的[DESC]部分可能会更容易,因为没有文件扩展名的文件名的剩余部分具有33个字符的固定长度.

Then I thought getting [DESC] part of file name could be done easier as the remaining part of file name without file extension has a fixed length of 33 characters.

@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,但是一行在备份文件夹中的6个文件上产生了相同的结果.

That batch file containing also ECHO left to command del in last but one line produces the same result on the 6 files in the backup folder.

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

I don't know if the batch file could be even more optimized without knowing which characters could exist in [DESC] part of the file names. I did not think about a possible further optimization.

让我们假设唯一的[DESC]字符串列表是众所周知的,并且可以在批处理文件中进行硬编码,例如,在我的测试案例中,这6个文件的2004 !Aprmodel%Subscribers=:/p>

Let us assume the list of unique [DESC] strings is well known and can be hard coded in the batch file, for example 2004 !Apr, model% and Subscribers= for the 6 files in my test case:

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

This batch file really deletes files because there is no ECHO in last but one line.

哦,是的,知道各个备份文件的名称将使一切变得容易得多.

Oh yes, knowing the individual backup file names makes everything much easier.

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

The batch file can be even optimized to a single command line:

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


最后让我们假设在备份存储介质上已创建:


Last let us assume on backup storage media is created:

  1. 每3个月对文件名为ComputerName_backup_YYYY_MM.tib的整个计算机进行一次备份,这相当于占用200 GiB的容量,并且足以在备份存储介质上仅进行最后一次备份;
  2. 每个文件的文件夹备份通常不使用文件名Folder_backup_YYYY_MM_DD.zip更新,这在存储介质上大约需要400 MiB的存储容量,足以恢复最近4周;
  3. 每天备份具有文件名Database_backup_YYYY_MM_DD.bak的数据库文件,每次备份耗时20 MiB,但与数据库文件和应该在哪里可以恢复数据条目的典型情况一样,它的常数或多或少地保持不变最近7天的时间.
  1. a backup of an entire machine with file name ComputerName_backup_YYYY_MM.tib every 3 months which is huge as taking 200 GiB and where it is enough to have only last backup on the backup storage media;
  2. a backup of a folder with files not often updated with file name Folder_backup_YYYY_MM_DD.zip every Saturday which takes about 400 MiB on storage media where it is enough to be able to restore the last 4 weeks;
  3. a backup of a database file with file name Database_backup_YYYY_MM_DD.bak every day which takes at the moment 20 MiB per backup, but is growing more or less constant as typical for database files and on where it should be possible to restore data entries of the last 7 days.

所需的最小存储媒体大小为:

The required minimum storage media size is:

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

根据数据库备份的增长速度,在接下来的三年中,存储介质大小为1 TiB确实足够了,计算中已经包括了3倍的增长.

A storage media size of 1 TiB is really enough for approximately the next 3 years depending on growing rate of database backup on which an increase by a factor of 3 is included already in calculation.

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

It would be best to delete all backup files no longer needed on creating the daily database backup to keep the backup files management simple by using a single and simple batch file.

@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

在考虑正确的策略时,删除不再需要的备份真的很容易.

Deletion of no longer needed backups can be really so easy on thinking about right strategy.

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

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.

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

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

Read also 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 lines to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line in a separate command process started in background.

这篇关于Bat文件仅在存在较新的文件时才删除文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆