我正在编写一个用于备份文件的批处理脚本,并且想要包含一种逻辑,如果备份数超过某个变量设置的某个特定数,该逻辑将删除文件夹中最旧的文件。批处理很新,一旦超出数量,我当前的代码就会删除所有文件。
任何想法如何做到这一点?
SET Count=0
FOR %%A IN ("%SNAPSHOTNAME%*.*") DO SET /A Count += 1
IF %Count% gtr %NumberOfBackups% FOR %%A IN ("%SNAPSHOTNAME%_PBCS_Test_*.*") DO del "%%A"
答案 0 :(得分:2)
对于此任务,我建议使用以下单个命令行:
for /F "skip=%NumberOfBackups% eol=| delims=" %%I in ('dir "%SNAPSHOTNAME%_PBCS_Test_*.*" /A-D-H /B /O-D 2^>nul') do del "%%I"
FOR 在后台以cmd.exe /C
开头的命令行中执行单独的命令过程:
dir "%SNAPSHOTNAME%_PBCS_Test_*.*" /A-D-H /B /O-D 2>nul
DIR 输出可逐行处理 STDOUT
/A-D-H
而不是隐藏文件(不是属性目录或隐藏文件)/B
而以裸格式显示,这意味着仅文件名 DIR 输出的用于处理 STDERR 的错误消息是通过使用2>nul
将其重定向到设备 NUL 来抑制的。
也请阅读有关Using Command Redirection Operators的Microsoft文章,以获取2>nul
的解释。当Windows命令解释器在执行命令之前处理此命令行时,重定向操作符>
必须在 FOR 命令行上使用脱字符号^
进行转义,才能被解释为文字字符。 FOR ,它将在后台启动的单独命令进程中执行嵌入式dir
命令行。
FOR 捕获此输出并根据双引号字符串中指定的选项逐行处理它,而忽略 DIR 的输出中不存在的空行
FOR 跳过了前%NumberOfBackups%
行,这意味着最新的%NumberOfBackups%
始终保留在当前目录中。
FOR 默认情况下也会忽略以分号开头的行,因为;
是行尾字符的默认设置。因此,eol=|
用于将行尾字符更改为竖线,这在文件或文件夹名称中是不可能的,因此 DIR 输出的文件名不可能以|
。
FOR 默认情况下,使用常规空格和水平制表符作为字符串定界符将行拆分为子字符串,并仅将第一个空格/制表符分隔的字符串分配给循环变量I
。可以通过在选项字符串末尾用delims=
指定一个空的定界符列表来获取分配给循环变量I
的整行(=文件名)来禁用此字符串拆分行为。
因此 DIR 会逐行输出所有匹配模式"%SNAPSHOTNAME%_PBCS_Test_*.*"
且名称为最新的文件,最后是最早的文件的所有非隐藏文件的名称,而 FOR 会忽略名称/最新的%NumberOfBackups%
文件,并删除所有其他较旧的文件。
%NumberOfBackups%
,则FOR 不执行任何操作。
要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。
del /?
dir /?
for /?
注意:这与Squashman所写的答案几乎相同,但有完整的解释。
答案 1 :(得分:1)
您的第二个for循环没有排序,也没有中断条件,因此正如您所提到的,它将删除所有文件。
dir
命令可以对文件进行排序,因此,取代对所有文件使用for
而不对for
命令的排序输出使用dir
。选项/OD
将按文件时间戳排序。
要让for循环处理输出,请使用for /f
。中断条件是仅删除第一个(在这种情况下为最旧的)文件,然后跳出for循环。
IF %Count% gtr %NumberOfBackups% for /f "delims=" %%f in ('dir /B /OD "%SNAPSHOTNAME%_PBCS_Test_*.*"') do del "%%f" & goto :gotIt
:gotIt
答案 2 :(得分:1)
如果使用带有SKIP选项的FOR / F命令,可以摆脱IF比较。
set "NumberOfBackups=6"
FOR /F "SKIP=%NumberOfBackups% DELIMS=" %%G IN ('DIR /A-D /B /O-D "%SNAPSHOTNAME%_PBCS_Test_*.*"') DO DEL "%%G"