我可以根据当前日期/时间生成目录名称:将这些值从WMIC获取到环境变量中以生成:
set BackDirName="%year%%month%%day%"
mkdir %BackDirName%
多次运行批处理后,我得到了许多目录,如:
20140901
20140908
...
20141127
我想只保留一些最新目录,删除旧目录。以下是它在一些抽象的伪PL中的表现:
rem in this PL array's items numbered starting from 1
declare var_dir_list:array of string
:start
rem listing all like 20YYMM* - I'll die before year 2100 :-)
list_dirs 20[1-9][0-9][0-1][0-9]* order:alphabetic direction:a-to-z
names_per_line:1 show:only-names =>var_dir_list
if number_of_lines(var_dir_list) GT 4 then
rem deleting first directory in list
remove_dir name:var_dir_list[1]
rem removing first line from list
var_dir_list=var_dir_list[2..number_of_lines(var_dir_list)]
goto start
end if
上面的伪代码迭代并删除除最后(最新)4个目录之外的所有目录。我需要使用内置的Windows批处理文件处理器来模拟此功能。但缺乏适当的文档(OMFG!为什么MS没有发布2008年的离线帮助,就像2003年那样?)让我很生气。 我不能依赖这些文件夹/文件的创建/修改日期,这就是我在名字中硬编码日期的原因。
如果可能的话,我不知道如何实现这样的功能。有什么实用的建议吗? (使用VBscript是可以接受的)
谢谢。
答案 0 :(得分:0)
此代码获取源目录中所有目录的列表(您必须指定此目录),按日期按相反顺序对它们进行排序,跳过前四个目录,然后删除其余目录。
@echo off
set source_dir="C:\Where\The\Directories\Are"
:: Takes a list of all directories in the source directory
:: /a:d grabs only directories
:: /:o-d sorts them in reverse by date (newest on top)
:: /b gets simple filenames so that this actually works
:: "skip=4" skips the first four listed
:: rd /s deletes recursively
:: /q forces the deletion without asking
:: and the rest are deleted
for /f "skip=4 tokens=* delims=" %%A in ('dir /a:d /o:-d /b %source_dir%') do rd /s /q %source_dir%\%%A
答案 1 :(得分:0)
这是我实施的解决方案。 它可能不是非常优化,但它可以工作并允许自定义。 我们赞赏优化。
首先,无论当前的语言环境如何,我都需要日期和时间。然后我制作了两个单独的文件来获取我需要的值。我可以将它们的代码写为主文件中的“子程序”,但这些代码片段是可重用的,我更喜欢将它们作为“外部库”。
GetDateTime.bat
rem GetDateTime.bat
rem Reading date and time into environment variables
rem This file should be CALLed from other .bats
for /f %%a in ('wmic path win32_localtime get dayofweek /format:list ^| findstr "="') do (set %%a)
for /f %%a in ('wmic path win32_localtime get day /format:list ^| findstr "="') do (set %%a)
for /f %%a in ('wmic path win32_localtime get month /format:list ^| findstr "="') do (set %%a)
for /f %%a in ('wmic path win32_localtime get year /format:list ^| findstr "="') do (set %%a)
for /f %%a in ('wmic path win32_localtime get hour /format:list ^| findstr "="') do (set %%a)
for /f %%a in ('wmic path win32_localtime get minute /format:list ^| findstr "="') do (set %%a)
rem echo -%dayofweek%-
rem echo %year%-%month%-%day% %hour%:%minute%
normalizeDT.bat
rem normalizeDT.bat
rem Normalize some values, adding leading zeros if needed
if /i %month% lss 10 (
set mon1=0%month%
) else (
set mon1=%month%
)
if /i %day% lss 10 (
set day1=0%day%
) else (
set day1=%day%
)
if /i %hour% lss 10 (
set hou1=0%hour%
) else (
set hou1=%hour%
)
if /i %minute% lss 10 (
set min1=0%minute%
) else (
set min1=%minute%
)
set month=%mon1%
set day=%day1%
set minute=%min1%
set hour=%hou1%
然后是主文件。它可能每次都会启动,但只在星期一创建新的备份。
weeklyFullBackup.bat
@echo off
@rem weeklyFullBackup.bat
@rem creating full/incremental backup
setlocal
@rem Base directory for creating subdirectories for backups
set BackUpBaseDir=d:\usrback
@rem The prefix for name of backup subdirectories
set BackDirNamePrefix=WBK
@rem How many old backups to store
set MaxBackNumber=4
@rem The directory to be backed up
set BackUpThis=c:\share
@rem Directory for storing RoboCopy logs
set RCLogDir=d:\var\log
@rem Reading date, time and the day of week (latter not used now, but may be used later)
@call getdatetime
@call normalizeDT
@rem Temporary files name - may differ from the name of backup directory!
set tempDT=%year%%month%%day%%hour%%minute%
@rem Resetting the flags, they can be set during ARGS parsing
set DoForce=
set DoNotPurge=
set ParametersAreCorrect=
@rem Parsing possible command line parameter
@rem Several ECHOS like "not forced" are for debugging purposes
if "%1"=="" (
echo No parameters. Behaving default.
set ParametersAreCorrect=YES
)
if "%1"=="/f" (
set DoForce=YES
set ParametersAreCorrect=YES
echo Forcing new backup
) else (
echo Not forced by /f
)
if "%1"=="/n" (
set DoNotPurge=YES
set ParametersAreCorrect=YES
echo Forcing NOT to purge old backups
) else (
echo Not forced by /n
)
if "%1"=="/fn" (
echo Forcing new backup
echo Forcing NOT to purge old backups
set DoForce=YES
set DoNotPurge=YES
set ParametersAreCorrect=YES
) else (
echo Not forced by /fn
)
if "%1"=="/?" (
:HelpAndExit
echo "%0 [/f|/n|/fn]"
echo /f - Force creation of new backup even if today is not Monday
echo /n - Not erase old backups
echo /fn - force and not erase
goto :eof
)
@rem ParametersAreCorrect become non-empy on acceptable parameter detection
@rem If the parameter is non-acceptable, we'll show the help and then quit
@rem It's weird to jump to a label inside compound operator, but it works.
if "%ParametersAreCorrect%"=="" (
echo Wrong parameters!
echo.
goto HelpAndExit
)
:WorkingNow
@rem Forcing creation of new backup if thoday is Monday
if "%DayOfWeek%"=="1" (
set DoForce=YES
echo Monday - Forcing new backup
)
@rem on Monday creating new subdirectory for new backup, on other day of week using last existing one
@rem If there was parameter /f or /fn, we pretend that today is Monday and forcing new backup
if "%DoForce%"=="YES" goto ItIsMonday
echo Not Monday, neither we forced to work, so will not create new backup subdir
@rem ==================================
@rem lookig for last backup subdirectory and using it
@rem sorting subdirs from oldest to newest to skip all but last one
dir /ad /b /on %BackupBaseDir%\%BackDirNamePrefix%*>"%tempDT%.tmp"
@rem FINDing the ":LPT:" string - it can't appear in file/directory name
type "%tempDT%.tmp"|find /c /v ":LPT:">"%tempDT%n.tmp"
@rem Setting environment variable from file
set /p NumOfDirs=<"%tempDT%n.tmp"
@rem Skipping all lines but last one
set /a NumOfDirs-=1
for /f "usebackq skip=%NumOfDirs%" %%I in (`type "%tempDT%.tmp"`) do (
echo Using [%%I]
set BackDirName=%%I
)
@rem ==================================
@rem we don't need to create new backup directory, then skipping the creation code
goto SkipMKDIR
:ItIsMonday
set BackDirName=%BackDirNamePrefix%%year%%month%%day%
if "%DayOfWeek%"=="1" (
echo "Today (%year%-%month%-%day%) is Monday"
) else (
echo "Today (%year%-%month%-%day%) is NOT Monday, but new backup is forced"
)
echo creating [%BackDirName%]
@rem On Mondays checking the existence of subdirectory - just for case
if exist "%BackupBaseDir%\%BackDirName%" (
echo dir is already exists [%BackupBaseDir%\%BackDirName%]
goto SkipMKDIR
)
echo dir is not exists [%BackupBaseDir%\%BackDirName%]
@rem To catch possible errors during MKDIR we turning off the extended commands handling:
@rem I will not create the entire path: if BaseDir not exists, then something is wrong
cmd /e:off /c mkdir %BackupBaseDir%\%BackDirName%
if errorlevel 1 (
echo Can't create dir [%BackupBaseDir%\%BackDirName%]
echo Aborting!
exit
)
:SkipMKDIR
@rem The backup itself
robocopy %BackUpThis% %BackupBaseDir%\%BackDirName% /copy:DATO /xf "~*.*" *.tmp *.wbk thumbs.db /xd ".recycle" /e /r:1 /w:5 /unilog:"%RCLogDir%\%TempDT%.RC.log" /dcopy:t /mt
set RoboErr=%errorlevel%
echo RoboCopy returned [%RoboErr%]
@rem RoboCopy's return codes taken here:
@rem http://technet.microsoft.com/en-us/library/cc733145%28v=ws.10%29.aspx
if /i %RoboErr% geq 8 (
echo Something wrong with this backup. NOT removing old backups, regardless of forsage state
echo Do not removing temporary files %TempDT%*.*
echo Consult log file [%RCLogDir%\%TempDT%.RC.log]
goto :eof
)
rem On successful new backup we may remove older ones.
if "%DoNotPurge%"=="YES" (
echo Forced to NOT remove old backups, skipping removal
goto SkipOldRemoval
)
@rem Very similar to above: getting list of existing backup directories and
@rem removing all but given number of them
dir /ad /b /o-n %BackupBaseDir%\%BackDirNamePrefix%*>"%tempDT%.tmp"
type "%tempDT%.tmp"|find /c /v ":LPT:">"%tempDT%n.tmp"
set /p NumOfDirs=<"%tempDT%n.tmp"
if /i %NumOfDirs% leq %MaxBackNumber% (
@rem Do nothing if there's not enough old backups
echo NOT removing old backups: %NumOfDirs% Less than %MaxBackNumber%.
goto SkipOldRemoval
)
@rem There's enough old backups, we should delete some
echo REMOVING old backups!: %NumOfDirs% Greater than %MaxBackNumber%
for /f "usebackq skip=%MaxBackNumber%" %%I in (`type "%tempDT%.tmp"`) do (
echo Removing [%%I]
rmdir /s /q %BackupBaseDir%\%%I
)
:SkipOldRemoval
@rem House cleaning
del "%tempDT%*.tmp"
endlocal