![使用logrotate](https://linux22.com/image/1582251/%E4%BD%BF%E7%94%A8logrotate.png)
我的目标是拥有一个 .bat,可以用来通过复制自动存档文件夹,使用当前日期重命名原始文件夹和其中的文件,然后清除旧的生产文件。
- 将目标文件夹复制到“完全的”目录
Previous Name_Today's Date
使用(MMDDYY)格式更新源文件夹的日期Current Name_Today's Date
使用格式(MMDDYY)更新源文件夹中 INDD 文件的日期- “干净的”删除源文件夹中的所有 .VPS 和 .PDF 文件
我是一个新手,但我根据研究和资料拼凑了这段代码:
@echo off
setlocal enabledelayedexpansion
for /f "skip=1" %%x in ('wmic os get localdatetime') do if not defined MyDate set MyDate=%%x
set today=%MyDate:~0,4%-%MyDate:~4,2%-%MyDate:~6,2%
xcopy /s /e /q /y "G:\...\Annual_*" "G:\...\_DONE\"
xcopy /s /e /q /y "G:\...\Life_*" "G:\...\_DONE\"
MOVE "G:\...\Annual_*" "G:\...\Annual_today"
MOVE "G:\...\Life_today" "G:\...\Life_today"
FOR /M *.indd /C "cmd /c rename @file \"@fname - today.indd\""
del /s "G:\...\Annual_today" *.pdf
del /s "G:\...\Annual_today" *.vps
del /s "G:\...\Life_today" *.pdf
del /s "G:\...\Life_today" *.vps
"G:\...\New_Job.bat" > output.txt
我的最终目标是能够更改源文件夹和存档文件夹的目录路径,以便我可以将此脚本重复用于不同的客户端文件。
当前的问题
就目前情况而言,脚本不会复制和创建存档文件夹文件,只是从所有目录中删除所有 VPS 和 PDF 文件,而不仅仅是目标文件夹。
我不确定我是否正确执行了日期检查,然后将其用作变量来重命名未来的文件夹和文件。
我不知道FOR /M *.indd /C "cmd /c rename @file \"@fname - today.indd\""
重命名文件是否正确。名称是采购订单号(6 位数字),然后是标题、下划线和日期。
例如 123456_Life_Kit_020819。
非常感谢您的帮助!
以下是脚本应执行的操作的示例
将整个文件夹复制到每个文件夹的 _OLD/Archive 文件夹中。然后将文件夹和内容扩展名重命名为“当前日期”。然后仅删除新日期目录中的 .pdf 和 .vps 文件。
这是文件夹结构的一个示例。
主目录:
在其中一个子目录内:
我尝试重命名的唯一内容是带有日期(复制后)的主目录文件夹以及子目录中的文件。
无需重命名其他文件夹。
答案1
我在下面包含了一个批处理脚本,它是一种混合脚本,因为它使用 PowerShell,但它动态地构建和执行它,但每个dest=
变量值的存档目标用于相应的处理。
我确实使用了一种方法Robocopy排除您想要从目标/存档文件夹中递归删除的文件扩展名类型,这样它就不会不必要地复制,因此无需删除。
我使用了大量 PowerShell 命令,因此,我并没有列出所有命令,而是将其中一些包含在更多资源如果您想进一步了解,请参阅其他学习部分。
批处理脚本
笔记:只需根据下面脚本顶部的相关变量(、和)设置源、目标和排除文件,然后单击
src=
即可dest=
运行。excludedFiles=
SET "src=G:\Folder\Production"
SET "dest=G:\Folder\__Archive"
SET "fname=*.*"
SET "excludedFiles=*.pdf *.vps"
Robocopy "%src%" "%fname%" "%dest%" /E /XF %excludedFiles%
CALL :PSScript
SET PowerShellDir=C:\Windows\System32\WindowsPowerShell\v1.0
CD /D "%PowerShellDir%"
Powershell -ExecutionPolicy Bypass -Command "& '%PSScript%'"
IF EXIST "%PSScript%" DEL /Q /F "%PSScript%"
EXIT
:PSScript
SET PSScript=%temp%\~tmp%~n0.ps1
IF EXIST "%PSScript%" DEL /Q /F "%PSScript%"
ECHO $Main ^= "%dest%"; >"%PSScript%"
ECHO $Today ^= ^(^("{0:MMddyy}" -f ^(get-date^).AddHours^(0^)^).ToString^(^)^) >>"%PSScript%"
ECHO $Folders ^= ^(Get-ChildItem -Directory $Main ^| ^? {$_ -match "([0-9]{6})"}^); >>"%PSScript%"
ECHO $Folders ^| %% { >>"%PSScript%"
ECHO If^($_ -match "([0-9]{6})"){ >>"%PSScript%"
ECHO $root ^= ^(Split-Path -path $_.Fullname^); >>"%PSScript%"
ECHO $oBase ^= ^(Split-Path -path $_.Fullname -leaf^); >>"%PSScript%"
ECHO $nBase ^= ^($oBase.Replace^($matches[1],$Today^)^); >>"%PSScript%"
ECHO Rename-Item "$root\$oBase" "$root\$nBase"; >>"%PSScript%"
ECHO } >>"%PSScript%"
ECHO }; >>"%PSScript%"
ECHO $Folders ^= ^(Get-ChildItem -Directory $Main ^| ^? {$_.Name -match "([0-9]{6})"}^).FullName; >>"%PSScript%"
ECHO $Files ^= ^($Folders ^| %% {Get-ChildItem "$_\*" -File -Include *.indd} ^| ^? {$_.Name -match "[0-9]{6}.*?([0-9]{6})"}^); >>"%PSScript%"
ECHO $Files ^| %% { >>"%PSScript%"
ECHO If^($_.Name -match "[0-9]{6}.*?([0-9]{6})"^) >>"%PSScript%"
ECHO { >>"%PSScript%"
ECHO $x ^= $matches[1]; >>"%PSScript%"
ECHO $root ^= ^(Split-Path -path $_.Fullname^); >>"%PSScript%"
ECHO $nName ^= ^($_.Name.Replace^($x,$today^)^); >>"%PSScript%"
ECHO If^(!^(Test-Path "$root\$nName"^)^){Rename-Item $_.FullName "$root\$nName"}; >>"%PSScript%"
ECHO } >>"%PSScript%"
ECHO }; >>"%PSScript%"
GOTO :EOF
PowerShell 逻辑
笔记:如果您想使用它,这是单独的 PowerShell,但您只需将
$Main =
变量值设置为文件夹和文件的存档文件夹路径,并mmddyy
使用运行时使用当前日期的字符进行更新的字符串。
$Main = "G:\Folder\__Archive";
$Today = (("{0:MMddyy}" -f (get-date).AddHours(0)).ToString())
$Folders = (Get-ChildItem -Directory $Main | ? {$_ -match "([0-9]{6})"});
$Folders | % {
If($_ -match "([0-9]{6})"){
$root = (Split-Path -path $_.Fullname);
$oBase = (Split-Path -path $_.Fullname -leaf);
$nBase = ($oBase.Replace($matches[1],$Today));
Rename-Item "$root\$oBase" "$root\$nBase";
}
};
$Folders = (Get-ChildItem -Directory $Main | ? {$_.Name -match "([0-9]{6})"}).FullName;
$Files = ($Folders | % {Get-ChildItem "$_\*" -File -Include *.indd} | ? {$_.Name -match "[0-9]{6}.*?([0-9]{6})"});
$Files | % {
If($_.Name -match "[0-9]{6}.*?([0-9]{6})")
{
$x = $matches[1];
$root = (Split-Path -path $_.Fullname);
$nName = ($_.Name.Replace($x,$today));
If(!(Test-Path "$root\$nName")){Rename-Item $_.FullName "$root\$nName"};
}
};
PowerShell 版本 2.0 兼容逻辑
批处理(PS 2.0)
笔记:只需根据下面脚本顶部的相关变量(、和)设置源、目标和排除文件,然后单击
src=
即可dest=
运行。excludedFiles=
SET "src=G:\Folder\Production"
SET "dest=G:\Folder\__Archive"
SET "fname=*.*"
SET "excludedFiles=*.pdf *.vps"
Robocopy "%src%" "%fname%" "%dest%" /E /XF %excludedFiles%
CALL :PSScript
SET PowerShellDir=C:\Windows\System32\WindowsPowerShell\v1.0
CD /D "%PowerShellDir%"
Powershell -ExecutionPolicy Bypass -Command "& '%PSScript%'"
IF EXIST "%PSScript%" DEL /Q /F "%PSScript%"
EXIT
:PSScript
SET PSScript=%temp%\~tmp%~n0.ps1
IF EXIST "%PSScript%" DEL /Q /F "%PSScript%"
ECHO $Main ^= "%dest%"; >"%PSScript%"
ECHO $Today ^= ^(^("{0:MMddyy}" -f ^(get-date^).AddHours^(0^)^).ToString^(^)^); >>"%PSScript%"
ECHO $Folders ^= ^(Get-ChildItem $Main ^| ^? {^($_.PSIsContainer^) -and ^($_ -match "([0-9]{6})"^)}^); >>"%PSScript%"
ECHO $Folders ^| %% { >>"%PSScript%"
ECHO If^($_ -match "([0-9]{6})"^){ >>"%PSScript%"
ECHO $root ^= ^(Split-Path -path $_.Fullname^); >>"%PSScript%"
ECHO $oBase ^= ^(Split-Path -path $_.Fullname -leaf^); >>"%PSScript%"
ECHO $nBase ^= ^($oBase.Replace^($matches[1],$Today^)^); >>"%PSScript%"
ECHO Rename-Item "$root\$oBase" "$root\$nBase"; >>"%PSScript%"
ECHO } >>"%PSScript%"
ECHO }; >>"%PSScript%"
ECHO $Folders ^= ^(Get-ChildItem $Main ^| ^? {^($_.PSIsContainer^) -and ^($_ -match "([0-9]{6})"^)}^); >>"%PSScript%"
ECHO $Files ^= ^($Folders ^| %% {Get-ChildItem $_.FullName -Recurse -Include *.indd ^| ^? {^(!$_.PSIsContainer^) -and ^($_.Name -match "[0-9]{6}.*?([0-9]{6})"^)}}^);>>"%PSScript%"
ECHO $Files ^| %% { >>"%PSScript%"
ECHO If^($_.Name -match "[0-9]{6}.*?([0-9]{6})"^) >>"%PSScript%"
ECHO { >>"%PSScript%"
ECHO $x ^= $matches[1]; >>"%PSScript%"
ECHO $root ^= ^(Split-Path -path $_.Fullname^); >>"%PSScript%"
ECHO $nName ^= ^($_.Name.Replace^($x,$today^)^); >>"%PSScript%"
ECHO If^(!^(Test-Path "$root\$nName"^)^){Rename-Item $_.FullName "$root\$nName"}; >>"%PSScript%"
ECHO } >>"%PSScript%"
ECHO }; >>"%PSScript%"
GOTO :EOF
PowerShell(PS 2.0)
轻松执行注意事项:将其保存为带有扩展名的文本文件
.ps1
到文件夹中,然后G:\Folder\Archiver.ps1
在 PowerShell 命令行中放置一个点、一个空格,然后用双引号括起来输入完整的脚本名称和路径,按Enter
。
$Main = "G:\Folder\__Archive";
$Today = (("{0:MMddyy}" -f (get-date).AddHours(0)).ToString());
$Folders = (Get-ChildItem $Main | ? {($_.PSIsContainer) -and ($_ -match "([0-9]{6})")});
$Folders | % {
If($_ -match "([0-9]{6})"){
$root = (Split-Path -path $_.Fullname);
$oBase = (Split-Path -path $_.Fullname -leaf);
$nBase = ($oBase.Replace($matches[1],$Today));
Rename-Item "$root\$oBase" "$root\$nBase";
}
};
$Folders = (Get-ChildItem $Main | ? {($_.PSIsContainer) -and ($_ -match "([0-9]{6})")});
$Files = ($Folders | % {Get-ChildItem $_.FullName -Recurse | ? {(!$_.PSIsContainer) -and ($_.Name -match "[0-9]{6}.*?([0-9]{6})")}});
$Files | % {
If($_.Name -match "[0-9]{6}.*?([0-9]{6})")
{
$x = $matches[1];
$root = (Split-Path -path $_.Fullname);
$nName = ($_.Name.Replace($x,$today));
If(!(Test-Path "$root\$nName")){Rename-Item $_.FullName "$root\$nName"};
}
};
更多资源
-
/S :: copy Subdirectories, but not empty ones. /E :: copy subdirectories, including Empty ones. /XF file [file]... :: eXclude Files matching given names/paths/wildcards.
- 称呼
- 获取子项
- 如果
-
标准别名对于 Foreach 对象:'
%
' 符号,ForEach -
'
?
' 符号和 Where 都是 Where-Object 的别名。如果您明确想要运行 Where-Object 命令,请运行 Where-object 或 '?
' 。 - 重命名项目
- 代替()
- 常用表达
- 测试路径
- 每第二次出现时匹配
答案2
我(终于)有一个 PowerShell 解决方案。
你应该创建 PowerShell 配置文件并将下面的函数放入其中。这样,无论何时启动 PowerShell,它都可以使用。
$Destination
将块中的路径更改Param()
为您想要的任何备份目标路径。
以下是一些如何使用该函数的示例:
# This will backup the specified path to the default destination specified in the function
Backup-Folder "C:\install\TestApp"
# You can also Backup multiple paths at once
Backup-Folder "C:\install\TestApp","D:\somepath\xy_020317"
# You can also overwrite the destination where the folder should be backed up to
Backup-Folder "C:\install\TestApp" -Destination "G:\MyNewFavoriteBackupLocation"
# You can also overwrite the setting for what Extensions to delete
Backup-Folder "C:\install\TestApp" -DeleteExtensions ".xlsx",".docx",".pdf"
# You can combine all of the above to be as flexible as you'd like
Backup-Folder "C:\install\TestApp","D:\somepath\xy_020317" -Destination "E:\xy" -DeleteExtensions ".ai"
顺便说一句。从你的评论中我感觉,你想要一个批处理调用,通过将这个函数放在你的 PowerShell 配置文件中,你可以*.bat
在任何你想要的地方(例如桌面或任何地方)创建一个文件,其中包含以下行:
powershell "Backup-Folder 'C:\foo\folder1', 'C:\bar\ANNUAL_323232', 'E:\somewhere'"
此功能将:
- 备份整个文件夹到
$Destination
$DeleteExtensions
删除文件夹中所有具有指定扩展名的文件- 检查是否必须更改文件夹及其文件的名称,否则不重命名
- 如果日期与之前不同,它将把文件夹和文件重命名为新日期
- 如果文件没有日期,它会添加它
这是完整注释的函数:
function Backup-Folder {
Param(
[ValidateScript({ Test-Path $_ })]
[string[]]$Path,
[string]$Destination = "C:\install\_DONE",
[string[]]$DeleteExtensions = @(".pdf",".vps")
)
# Creating Destination Directory if not already present
mkdir $Destination -ErrorAction SilentlyContinue > $null
# Getting the Date.
$Date = (Get-Date).ToString("MMddyy")
# Looping over each path
foreach ($p in $path) {
# Copy the whole folder to the destination
Copy-Item $p $Destination -Recurse -Force
# Get Folder Data
$Folder = Get-Item $p
# Get Old and New Name
$Folder.Name -match '\d{6}' > $null
$Old = $Matches.GetEnumerator() | select -expand Value
$New = if ($Old) { $Folder.Name -replace $Old,$Date }
else { "{0}_{1}" -f $Folder.Name,$Date }
# if the Old Date is not the same as the new date Rename Folders and return them
# else return the original folder object
$RenamedFolder = if ($Old -ne $Date) { Rename-Item $Folder -NewName $New -PassThru }
else { $Folder }
# Get all Files in subfolder and loop over them
# Add -Recurse after $RenamedFolder if you also want the script to go through
# all files of all subdirectories
Get-ChildItem $RenamedFolder | ? { !$_.PsIsContainer } | foreach {
# if the extension should be deleted, delete it
if ($_.Extension -in $DeleteExtensions) {
# Delete Item
Remove-Item $_.FullName -Force
}
# else rename it.
else {
# Get Old and New Name
$_.BaseName -match '\d{6}' > $null
$OldName = $Matches.GetEnumerator() | select -expand Value
$NewName = if ($OldName) { $_.Name -replace $OldName,$Date }
else { "{0}_{1}{2}" -f $_.BaseName,$Date,$_.Extension }
# Finally Rename Item if the Old Date is not the same as the new date
if ($OldName -ne $Date) { Rename-Item $_.FullName -NewName $NewName }
}
}
}
}
我们还可以添加一个逻辑来指定应该保留哪些文件扩展名,另外如果您认为有必要的话,还可以告诉您哪些文件扩展名应该被删除。
答案3
我有一个 powershell 解决方案给你。
归档器.ps1,归档程序,然后使用命令 shell 行启动它。将 PS1 文件和 BAT 文件放在同一个文件夹中(您选择的任何位置)。重命名的目的是为了使用下划线和 6 位数字“_######”。
BAT文件有4个参数:
您希望递归搜索基于的根文件夹。
要修改的文件/文件夹名称子部分例如:“Annual_”
要修改的第二个文件/文件夹名称子部分示例:“Life_”
要创建/添加的存档文件夹的名称。例如:“_OLD”
文件Archiver.ps1:
Param(
[Parameter(Position=0)] [string]$rootFolder = "C:\scripting\archiver"
,[Parameter(Position=1)] [string]$folderName1 = "ANNUAL_"
,[Parameter(Position=2)] [string]$folderName2 = "LIFE_"
,[Parameter(Position=3)] [string]$archiveFolder = "_OLD"
)
BEGIN
{
$today = get-date -UFormat %m%d%y
$folderName1 = "*"+$folderName1+"*"
$folderName2 = "*"+$folderName2+"*"
$startFolders = GCI -Path $rootFolder -Recurse -Include $folderName1, $folderName2 -Exclude $archiveFolder -Directory
pushd
foreach ($fold in $startFolders){
cd $fold
if(-not (Test-Path $archiveFolder)){md $archiveFolder | Out-Null}
$theseFilez = gci -File
if($theseFilez){
foreach ($filez in $theseFilez){
Copy-Item $filez $archiveFolder -Force
if($filez -like "*.indd" -and $filez -notlike "*_$today*"){$filez | Rename-Item -NewName {$filez.Name -replace '[_]\d{6}',('_'+$today)}}
}
Remove-Item "*.pdf"
Remove-Item "*.vps"
}
if($fold -notlike "*_$today*"){$fold | Rename-Item -NewName {$fold.Name -Replace '[_]\d{6}',('_'+$today)}}
}
popd
}
PROCESS{}
END{}
文件 Archiver.Bat(1 行)
start powershell -File Archiver.ps1 -rootFolder "%1" -folderName1 "%2" -folderName2 "%3" -archiveFolder "%4"
命令 Shell 调用:
archiver c:\scripting\archiver LIFE_ ANNUAL_ _OLD
或者对于双击运行的批处理文件,只需在批处理文件中输入参数,如下所示:
start powershell -File Archiver.ps1 -rootFolder "C:\scripting\archiver" -folderName1 "ANNUAL_" -folderName2 "LIFE_" -archiveFolder "_OLD"
编辑将第二个 gci 命令中的“-Exclude $archiveFolder”更改为“-File”
编辑 2 - 调整两个文件/文件夹名称,还包括用于“双击”运行的批处理文件。
按照 SimonS 的建议,编辑 3 将日/月/年替换为月/日/年。
答案4
使用logrotate
这正是它的用途......
配置文件logrotate.conf
/tmp/mydir/* {
daily
dateext
olddir /tmp/myarchive
}
然后运行它。
touch /tmp/mydir/mylog1.txt /tmp/mydir/myotherlog2.txt
logrotate -vf ./logrotate.conf -s mystatus.logrotate
您应该在详细模式下看到类似这样的内容
reading config file ./logrotate.conf
olddir is now /tmp/myarchive
Reading state from file: mystatus.logrotate
Allocating hash table for state file, size 64 entries
Creating new state
Creating new state
Creating new state
Creating new state
Handling 1 logs
rotating pattern: /tmp/mydir/* forced from command line (no old logs will be kept)
olddir is /tmp/myarchive, empty log files are rotated, old logs are removed
considering log /tmp/mydir/mylog1.txt
Now: 2019-02-18 00:08
Last rotated at 2019-02-18 00:00
log needs rotating
considering log /tmp/mydir/myotherlog2.txt
Now: 2019-02-18 00:08
Last rotated at 2019-02-18 00:00
log needs rotating
rotating log /tmp/mydir/mylog1.txt, log->rotateCount is 0
dateext suffix '-20190218'
glob pattern '-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
glob finding old rotated logs failed
renaming /tmp/mydir/mylog1.txt to /tmp/myarchive/mylog1.txt-20190218
disposeName will be /tmp/myarchive/mylog1.txt-20190218
removing old log /tmp/myarchive/mylog1.txt-20190218
rotating log /tmp/mydir/myotherlog2.txt, log->rotateCount is 0
dateext suffix '-20190218'
glob pattern '-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
glob finding old rotated logs failed
renaming /tmp/mydir/myotherlog2.txt to /tmp/myarchive/myotherlog2.txt-20190218
disposeName will be /tmp/myarchive/myotherlog2.txt-20190218
removing old log /tmp/myarchive/myotherlog2.txt-20190218
logrotate
已在所有 Linux 系统上运行。它可能已在您的系统上运行(请参阅/etc/logrotate.conf
或/etc/logrotate.conf.d/
),并且您可以在 Windows 上使用以下命令安装它:Logwot8