1

我创建了一个批处理文件,目的是精简旧的备份文件。更具体地说,该脚本会识别上次修改日期在 183 到 365 天之间的备份文件,在整个 6 个月期间内每 7 天删除所有 bar 一个文件。如果在 7 天内有零个或一个文件,则不会删除任何文件。

该脚本基本上可以工作,但依赖于一个临时文件来存储每 7 天的匹配文件的文件名。我想知道是否可以修改脚本以在不需要临时文件的情况下执行相同的操作。

该脚本的灵感来自aschipfl解决FORFILES设计缺陷的答案中描述的技术。这种技术有效地增强FORFILES了 ,因此它可以识别在两个日期(或几天)之间最后修改的文件。我看到的困难在于FORFILES“文件识别”输出被重定向到CON设备。这意味着输出不可用于FOR /F循环进行进一步处理。所以我的“快速修复”是将输出重定向到一个临时文件,FOR /F循环可以访问该文件。我想知道是否可以插入一些文件描述符魔术来利用输出到FOR.

这是我的(非破坏性)脚本:

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET BACKUPFILEMASK=*.7z
SET DAYS_OLD_EARLIEST=183
SET DAYS_OLD_LATEST=365
SET TMPFILENAME=thin_out_logging.txt

FOR /L %%A IN (%DAYS_OLD_EARLIEST%,7,%DAYS_OLD_LATEST%) DO (
    ECHO Iteration: %%A
    SET /A ADDWEEK=%%A+7
    >NUL 2>&1 FORFILES /M %BACKUPFILEMASK% /D -%%A /C "CMD /C IF @ISDIR==FALSE 2>NUL FORFILES /M @FILE /D -!ADDWEEK! || >> "%TMP%\%TMPFILENAME%" ECHO @FILE"
    FOR /F %%B IN ('TYPE "%TMP%\%TMPFILENAME%" ^| FIND "" /V /C') DO SET /A LINES=%%B
    ECHO Lines counted for week: !LINES!
    IF !LINES! GEQ 2 (
    FOR /F "skip=1 usebackq tokens=*" %%C IN ("%TMP%\%TMPFILENAME%") DO ECHO DEL %%C
    ) 
    ECHO ---
    BREAK>"%TMP%\%TMPFILENAME%"
)
DEL "%TMP%\%TMPFILENAME%"
4

1 回答 1

0

经过多次试验,我终于搞定了。使其发挥作用的关键调整是:

  • 将线包裹FORFILES在一个FOR /F循环中
  • 使用FOR /Fwith来禁止打印以外部eol=".find 开头的不需要的文件。这取代了它也抑制了我想要打印的文件。"FORFILES>NUL 2>&1
  • 对我想要打印的文件使用前缀字符,这样它们就不会被FOR /F'eol="选项丢弃。"几乎可以使用任何非字符。我选择了波浪字符:(ECHO ~DEL @FILE非破坏性版本的线)
  • 在每次迭代时使用变量进行计数和递增。然后仅在变量为GEQto时打印2,以便根据需要跳过第一个找到的文件。这将替换skip=1修订后的代码中没有预期效果的内容。
@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET BACKUPFILEMASK=*.7z
SET DAYS_OLD_EARLIEST=183
SET DAYS_OLD_LATEST=365
FOR /L %%A IN (%DAYS_OLD_EARLIEST%,7,%DAYS_OLD_LATEST%) DO (
    ECHO Iteration: %%A
    SET /A ADDWEEK=%%A+7
    SET /A COUNT=0
    FOR /F ^"eol^=^"^ tokens^=^*^ delims^=^~^" %%B IN ('2^>NUL FORFILES /M %BACKUPFILEMASK% /D -%%A /C ^"CMD /C IF @ISDIR^=^=FALSE 2^>NUL FORFILES /M @FILE /D -!ADDWEEK! ^|^| ECHO ~DEL @FILE^"') DO (
        SET /A COUNT+=1
        IF !COUNT! GEQ 2 ECHO %%B
    )
    ECHO ---
)

样本输出:

Iteration: 183
DEL "Notes_backup_18112020_0837.7z"
DEL "Notes_backup_19112020_0832.7z"
DEL "Notes_backup_20112020_0844.7z"
DEL "Notes_backup_21112020_0955.7z"
DEL "Notes_backup_22112020_1339.7z"
DEL "Notes_backup_23112020_0941.7z"
---
Iteration: 190
DEL "Notes_backup_11112020_0907.7z"
DEL "Notes_backup_12112020_0930.7z"
DEL "Notes_backup_13112020_0844.7z"
DEL "Notes_backup_14112020_0916.7z"
DEL "Notes_backup_15112020_1022.7z"
DEL "Notes_backup_16112020_0905.7z"
---

要真正删除这些文件,而不是仅仅将DEL命令打印到控制台,替换ECHO ~DELECHO ~,并替换IF !COUNT! GEQ 2 ECHO %%BIF !COUNT! GEQ 2 DEL %%B

可以理解,这对于我以外的任何人来说可能很难测试,因为需要一系列具有正确修改日期的每日备份文件。因此,如果有人有兴趣对此进行测试,这里有一些 Powershell(多么讽刺)来创建测试文件,并将修改日期设置为过去 365 天内的每一天:

for($i=1; $i -le 365; $i++)
{
    $date = (Get-Date).AddDays(-1-$i)
    $filedate = $date.ToString('yyyy-MM-dd') 
    $file = New-Item -Path . -Name "${i}.7z" -ItemType File
    $file.LastWriteTime = $date
}

要使用,请将代码保存到某个位置的.ps1文件中,保存cd到要创建文件的目录中,然后通过键入类似powershell -ExecutionPolicy ByPass -File C:\path\to\script.ps1.

于 2021-05-25T17:57:22.857 回答