我有许多文件,每天使用不同的名称。如何根据名称中的日期进行筛选?
例如:
app_20130505.log
app_20130506.log
app_20130507.log
app_20130508.log
app_20130509.log
我的代码片段:
$RetainedDays = 7
$FileNameRegex = "\w+_(\d+)\.\w+"
$ArchiveBoundary = $(Get-Date -Format yyyyMMdd) - $RetainedDays
$ProcessFiles = Get-ChildItem -Path $RootPath -Recurse |
Where-Object { $_.Name -match $FileNameRegex }
我有它的正则表达式过滤器:\w+_(\d+)\.\w+
,它返回 $Matches 变量中的日期,但是我如何将它们组合起来,并返回包含超过 7 天的文件的文件列表?
答案1
我意识到这是一个 4 年前的问题。但我认为我应该添加一个新答案,因为目前没有其他获得支持答案。
我的做法是将日期DateTime
从文件名解析为实际对象。然后,您可以使用普通的日期比较,而不是字符串比较。最常见的方法是使用计算属性作为语句的一部分Select-Object
。在下面的示例中,我们ParsedDate
向现有输出添加了一个名为的计算属性。
$RetainedDays = 7
$FileNameRegex = "\w+_(\d+)\.\w+"
$culture = [System.Globalization.CultureInfo]::InvariantCulture
$ProcessFiles = Get-ChildItem -Path $RootPath -Recurse |
Select-Object *,@{
L='ParsedDate';
E={ if ($_.Name -match $FileNameRegex) {
$strDate = $matches[1];
[DateTime]::ParseExact($strDate,"yyyyMMdd",$culture)
}
}
} | Where { $_.ParsedDate -lt (Get-Date).AddDays(-$RetainedDays) }
正则表达式实际上使事情变得比实际更复杂。如果你的文件都具有完全相同的命名模式app_<日期>.log,您可以跳过正则表达式,通过让其ParseExact
完成所有工作来简化。您只需用单引号将格式字符串中的文字字符括起来即可对其进行转义。
$RetainedDays = 7
$culture = [System.Globalization.CultureInfo]::InvariantCulture
$ProcessFiles = Get-ChildItem -Path $RootPath -Recurse | Select FullName,@{
L='ParsedDate';
E={ [DateTime]::ParseExact($_.Name,"'app_'yyyyMMdd'.log'",$culture) }
} | Where { $_.ParsedDate -lt (Get-Date).AddDays(-$RetainedDays) }
从技术上讲,您也可以在 Where 子句内进行日期解析并跳过中间的 Select 子句。但我将这留给读者作为练习。
答案2
看看这是否有助于您更接近您想要做的事情。
$RootPath = "C:\temp"
$ProcessFiles = @()
$RetainedDays = 7
$Today = get-date -format yyyyMMdd
$FileNameRegex = "\w+_(\d+)\.\w+"
foreach ($File in Get-ChildItem -Path $RootPath) {
$match = [regex]::matches($File, $FileNameRegex )
$FileNameDate = $match[0].Groups[1].Value
if (($Today - $FileNameDate) -ge $RetainedDays) { $ProcessFiles += $File }
}
$ProcessFiles
答案3
虽然不太好,但是很管用!:)
$RetainedDays = 14
$ArchiveBoundary = (Get-Date).AddDays(-$RetainedDays).ToString('yyyyMMdd')
$ProcessFiles = Get-ChildItem -Path $RootPath -Recurse |
Where-Object { ($_.BaseName -split '_|\.')[1] -lt $ArchiveBoundary }