在文件夹内(例如c:\ test)如果文件数超过21,我想删除最旧的文件。
这是我想出的,问题是它一次删除最旧的文件,第二次运行它什么也没做,删除最旧的第三个,继续这样。它也不关心文件数量是否低于21,即使它更低也会删除。
以下是代码:
SET BACKUPDIR=C:\test
SET countfiles=dir BACKUPDIR /b | find /v /c "::"
if countfiles GTR 21 (
FOR /F %%i IN ('DIR /B /O-D %BACKUPDIR%') DO SET OLDEST=%%i
DEL %BACKUPDIR%\%OLDEST%
)
答案 0 :(得分:4)
这有很多问题。
环境变量与文字字符串:
SET countfiles=dir BACKUPDIR /b | find /v /c "::"
在这里,您尝试列出名为“BACKUPDIR”的目录中的文件,而不是使用环境变量。它应该是
SET countfiles=dir %BACKUPDIR% /b | find /v /c "::"
您尝试获取文件数:
SET countfiles=dir %BACKUPDIR% /b | find /v /c "::"
不可能奏效。这只是将字符串'dir BACKUPDIR /b | find /v /c "::"
'
分配给环境变量countfiles
。它不会运行任何东西 - cmd
应该如何知道这是一个执行命令?
您想要的是以下内容:
for /f %%x in ('dir %BACKUPDIR% /b ^| find /v /c "::"') do set countfiles=%%x
这会将countfiles
环境变量的内容设置为上述命令的输出。您可以使用help for
找到更多相关信息。
您的比较:
if countfiles GTR 21
比较字符串 "countfiles"
和字符串"21"
。由于countfiles
在21
之后排序,因此这种情况将始终为真。
您想在此处使用环境变量%countfiles%
:
if %countfiles% GTR 21
您在“块”中尝试“正常”变量扩展:
if %countfiles% GTR 21 (
FOR /F %%i IN ('DIR /B /O-D %BACKUPDIR%') DO SET OLDEST=%%i
DEL %BACKUPDIR%\%OLDEST%
)
由于cmd
在解析命令时会立即扩展环境变量,因此会导致问题。请注意,上面的块计为cmd
的单个命令。完整的块将在运行之前进行解析,并且内部的所有变量在运行时都已被替换,因此这不是处理可能会更改内部块的变量的正确方法。
此处的解决方案是延迟扩展。您可以在批次开头包含以下行:
setlocal enabledelayedexpansion
而不是使用像%OLDEST%
这样的变量,而是使用!OLDEST!
。 !
也扩展变量,但是在执行之前直接执行,而不是在解析时执行。所以你的代码片段会变成:
if %countfiles% GTR 21 (
FOR /F %%i IN ('DIR /B /O-D %BACKUPDIR%') DO SET OLDEST=%%i
DEL %BACKUPDIR%\!OLDEST!
)
如果您希望文件名包含空格,则最后一个块中的for /f
循环无法按预期工作。您可以像这样修改它:
for /f "delims=" %%i in ...
这可以确保该行不会在空格处被破坏(您只需要第一个令牌 - 文件名中的第一个空格 - 而不是完整的文件名。
总而言之,您的程序可能如下所示:
SET BACKUPDIR=C:\test
for /f %%x in ('dir %BACKUPDIR% /b ^| find /v /c "::"') do set countfiles=%%x
if %countfiles% GTR 21 (
FOR /F "delims=" %%i IN ('DIR /B /O-D %BACKUPDIR%') DO SET OLDEST=%%i
DEL %BACKUPDIR%\!OLDEST!
)
并且应该大致工作。我没有测试它的每个方面(床上电话),但我相信它比以前好多了,我希望你能理解上面的修复以及为什么它们是必要的。
顺便说一下:find /v /c "::"
是一个漂亮的小技巧。不知道那一个还是想到它。
以防万一:如果你真的想继续删除最旧的文件,直到你的文件数量低于21,那么那个单if
将不会删除它。您需要设置循环,方法是继续迭代并重新计算每次迭代,或者只计算要删除的文件数。不过,我会把它留作练习。 (提示:循环可以使用标签和条件goto
或使用for /l
来完成。后者需要更多延迟扩展,所以要小心。)
答案 1 :(得分:1)
这是vbscript的另一种选择,它只迭代目录一次。
Set objFS=CreateObject("Scripting.FileSystemObject")
Set objArgs = WScript.Arguments
strFolder = objArgs(0)
strScriptName = WScript.ScriptFullName 'get script name
Set objFolder = objFS.GetFolder(strFolder)
Set dict = CreateObject("Scripting.Dictionary")
current = Now
temp=0
count=0 'count files
For Each strFile In objFolder.Files
If strFile.Path <> strScriptName Then 'do if not script name
count=count+1
dict.Add strFile.Path, strFile.DateLastModified
'if there are more than 21 files
If count >= 21 Then
flag=1
End If
End If
Next
filedate = dict.Items
filename = dict.keys
If flag = 1 Then
For i = 0 To dict.Count -1 'iterate dictionary
diffdate = DateDiff("d",filedate(i),now)
If num_days_diff >= temp Then
oldestfile = filename(i)
oldestdate = filedate(i)
temp = num_days_diff
End If
Next
End If
Set dict=Nothing
WScript.Echo "Oldest file: " & oldestfile, oldestdate
objFS.DeleteFile(oldestfile)
另存为deletefile.vbs并在命令行中
c:\test> cscript /nologo deletefile.vbs c:\path\somewhere