繁体   English   中英

Windows 批处理文件:FORFILES“日期之间”解决方法 - 如何使 >CON output 可用于 FOR 循环

[英]Windows Batch file: FORFILES “date between” workaround - how to make >CON output available to FOR loop

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

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

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

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

  • FOR /F循环中包装FORFILES
  • 使用FOR /Feol="来禁止打印外部FORFILES找到的以"开头的不需要的文件。 这替换了>NUL 2>&1 ,这也抑制了我想要打印的文件。
  • 想要打印的文件使用前缀字符,这样它们就不会被FOR /Feol="选项丢弃。几乎任何非"字符都可以使用。 我选择了波浪字符: ECHO ~DEL @FILE (行的非破坏性版本)
  • 在每次迭代时使用变量进行计数和递增。 然后仅在变量为GEQ to 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 ---
)

样品 output:

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 ~DEL替换为ECHO ~ ,并替换IF !COUNT! GEQ 2 ECHO %%B 带有IF !COUNT! GEQ 2 DEL %%BIF !COUNT! GEQ 2 ECHO %%B IF !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
}

To use, save the code to a .ps1 file somewhere, cd into the directory where you want to create the files and run the Powershell by typing something like powershell -ExecutionPolicy ByPass -File C:\path\to\script.ps1 .

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM