如何删除 Powershell 中特定日期之前的所有记录(行)?
How to delete all records(rows) before specific date in powershell?
我正在尝试编写一个代码,根据列 8.My 中存储的文本字符串删除特定日期(日期存储在第 1 列)之前的所有行文本文件确实很大(超过800 000 行)所以我不确定我的代码是否是最好的方法。到目前为止,我的代码只是删除 $date1.
之前的所有行
$date1 = Read-Host 'Enter date1 mm/dd/yyyy'
$date2 = Read-Host 'Enter date2 mm/dd/yyyy'
$header="Date,Header2,Header3,Header4,Header5,Header6,Header7,Header8" | Out-File test.txt -encoding "Default"
get-content .\bigfile.txt |select -Skip 1 | where { [datetime]($_.split(','))[0] -ge $date1} | Out-File test.txt -encoding "Default" -append
因此,对于第 8 列中最后 3 个字符为“-XX”或“.YY”的文本字符串,应删除 $date1 之前的所有行。对于第 8 列中最后 3 个字符不是 "-XX" 或 ".YY" 的文本字符串,应删除 $date2 之前的所有行。
我真的希望我的描述足够清楚。如果不是,我很抱歉。
请看下面的测试文件:
bigfile.txt
Date,Header2,Header3,Header4,Header5,Header6,Header7,Header8
8/14/2014,11.4,11.4,11.07,11.11,52930,0,Text1
8/15/2014,11.18,11.18,10.78,10.81,80517,0,Text1
8/18/2014,10.92,11.12,10.81,11,188671,0,Text1
8/14/2014,11.09,11.79,11.036,11.49,142205,0,Text2-XX
8/15/2014,11.43,11.738,11.32,11.7,70846,0,Text2-XX
8/16/2014,11.67,12.56,11.458,12.42,170739,0,Text2-XX
8/17/2014,12.47,12.79,12.22,12.66,176367,0,Text2-XX
8/14/2014,12.7,13.5,12.6,13.26,411410,0,Text3
8/15/2014,13.35,13.62,13.17,13.55,209561,0,Text3
8/16/2014,13.55,13.57,13.28,13.49,104880,0,Text3
8/14/2014,13.4,13.61,13.14,13.18,167355,0,Text4.YY
8/15/2014,13.17,13.17,12.67,13.04,119659,0,Text4.YY
8/16/2014,13.07,13.07,12.64,12.73,133181,0,Text4.YY
8/15/2014,12.75,13.43,12.75,13.38,154302,0,Text5
8/16/2014,13.43,13.78,13.28,13.49,203535,0,Text5
8/17/2014,13.43,14.29,13.38,14.24,167803,0,Text5
8/18/2014,14.26,14.53,13.79,13.91,124665,0,Text5
8/19/2014,13.87,13.95,13.25,13.3,123747,0,Text5
8/20/2014,13.27,13.45,12.79,12.94,128408,0,Text5
8/21/2014,12.81,13.22,12.81,13.1,74911,0,Text5
8/15/2014,13.09,13.26,12.81,13.01,204025,0,Text5.YY
8/16/2014,13.07,13.07,12.58,12.64,75625,0,Text5.YY
8/17/2014,12.52,13.26,12.52,13.26,115968,0,Text5.YY
这是一个简单的Import-CSV
,一个使用分组的Where
语句,正则表达式匹配,分组内的-and
条件,以及它们之间的-or
条件。类似于:
Import-CSV .\bigfile.txt |
where { ($_.Header8 -match "(-XX|\.YY)$" -and ([datetime]$_.Date) -ge $date1) -or ($_.Header8 -notmatch "(-XX|\.YY)$" -and ([datetime]$_.Date) -ge $date2) } |
Export-Csv test.txt -NoTypeInformation -append
编辑: 正如 Matt 指出的那样,我的日期比较逻辑存在缺陷,因为它将文件中的文本视为字符串。我更新了我的代码来解决这个问题。
话虽这么说,看在上帝的份上,请使用 Matt 的回答代替我的回答! 我没有看到您的文件中有 800,000 行要更新。我的回答应该可以正常工作,但它会慢得令人痛苦,因为它将整个文件转换为一个对象数组,解析它们,然后一次将它们全部写回。我留下答案是因为它是实用的,但更适合较小的文件。
Edit2: 好吧,如果你没有看到 Matt 的代码有任何性能提升(你可能想在他的代码中将 ReadCount 更改为 1000 或 2000),这里更新了我的代码将在将其写回文件之前删除多余的引号。
(Import-CSV C:\temp\new.txt |
where { ($_.Header8 -match "(-XX|\.YY)$" -and ([datetime]$_.Date) -ge $date1) -or ($_.Header8 -notmatch "(-XX|\.YY)$" -and ([datetime]$_.Date) -ge $date2) } |
ConvertTo-Csv -NoTypeInformation) -replace '"'|
set-content $output
我希望这在您拥有 1000 行数据的情况下可能会表现得更好。唯一的规定是您应该手动从文件中删除第一行数据,因为这种方法以块的形式读取行并且对每一行都有一个 if 语句来检查 header 似乎是一种浪费
$output = C:\temp\test.txt
$date1 = Read-Host 'Enter date1 mm/dd/yyyy'
$date2 = Read-Host 'Enter date2 mm/dd/yyyy'
Set-Content -Path $output -Value "Date,Header2,Header3,Header4,Header5,Header6,Header7,Header8"
Get-Content C:\temp\data.log -ReadCount 500 | ForEach-Object{$_} | ForEach-Object{
$line = $_
$splitLine = $line -split ","
$singleDate = [datetime]$splitLine[0]
$queryColumn = $splitLine[7]
If (($queryColumn -match "(-XX|\.YY)$" -and $singleDate -ge $date1) -or ($queryColumn -notmatch "(-XX|\.YY)$" -and $singleDate -ge $date2)){
$line
}
} | Add-Content $output
我发誓我没有盗用 Mads 的逻辑。
帐号为header
我想不出一个巧妙的方法来使用 if
语句来处理 header 期望值。 不应该 增加太多的处理时间。
Get-Content C:\temp\data.log -ReadCount 500 | ForEach-Object{$_} | ForEach-Object{
If($_ -notmatch "header"){
$line = $_
$splitLine = $line -split ","
$singleDate = [datetime]$splitLine[0]
$queryColumn = $splitLine[7]
If (($queryColumn -match "(-XX|\.YY)$" -and $singleDate -ge $date1) -or ($queryColumn -notmatch "(-XX|\.YY)$" -and $singleDate -ge $date2)){
$line
}
}
} | Add-Content $output
我知道这个问题已经得到解答,但看起来很有趣。此外,此方法可能会提供更好的性能。我正在使用 IO.StreamReader 获取文件并逐行解析并使用 IO.StreamWrite 立即输出结果。我还没有验证条件..
$date1 = Read-Host 'Enter date1 mm/dd/yyyy'
$date2 = Read-Host 'Enter date2 mm/dd/yyyy'
$filePath = "path\to\bigfile.txt"
$outputfile = "outfile.txt"
$file = New-Object System.IO.StreamReader -Arg "$filePath"
$outFile = New-Object System.IO.StreamWriter -arg "$outputfile"
while ($line = $file.ReadLine()) {
$line | % {
$items = $_.Split(',')
try{
[datetime]$rowDate = $items[0]
[string]$Header8 = $items[-1]
If($rowDate -le $date1 -and $Header8 -match "-XX|.YY")
{$null}
ElseIf($rowDate-le $date2 -and $Header8 -notmatch "-XX|.YY")
{$null}
Else {
$outItem = $items -join ","
$outFile.WriteLine($outItem)}
}
catch [System.Exception] {$null}
}
}
$file.close()
$outFile.Close()
我正在尝试编写一个代码,根据列 8.My 中存储的文本字符串删除特定日期(日期存储在第 1 列)之前的所有行文本文件确实很大(超过800 000 行)所以我不确定我的代码是否是最好的方法。到目前为止,我的代码只是删除 $date1.
之前的所有行$date1 = Read-Host 'Enter date1 mm/dd/yyyy'
$date2 = Read-Host 'Enter date2 mm/dd/yyyy'
$header="Date,Header2,Header3,Header4,Header5,Header6,Header7,Header8" | Out-File test.txt -encoding "Default"
get-content .\bigfile.txt |select -Skip 1 | where { [datetime]($_.split(','))[0] -ge $date1} | Out-File test.txt -encoding "Default" -append
因此,对于第 8 列中最后 3 个字符为“-XX”或“.YY”的文本字符串,应删除 $date1 之前的所有行。对于第 8 列中最后 3 个字符不是 "-XX" 或 ".YY" 的文本字符串,应删除 $date2 之前的所有行。 我真的希望我的描述足够清楚。如果不是,我很抱歉。
请看下面的测试文件: bigfile.txt
Date,Header2,Header3,Header4,Header5,Header6,Header7,Header8
8/14/2014,11.4,11.4,11.07,11.11,52930,0,Text1
8/15/2014,11.18,11.18,10.78,10.81,80517,0,Text1
8/18/2014,10.92,11.12,10.81,11,188671,0,Text1
8/14/2014,11.09,11.79,11.036,11.49,142205,0,Text2-XX
8/15/2014,11.43,11.738,11.32,11.7,70846,0,Text2-XX
8/16/2014,11.67,12.56,11.458,12.42,170739,0,Text2-XX
8/17/2014,12.47,12.79,12.22,12.66,176367,0,Text2-XX
8/14/2014,12.7,13.5,12.6,13.26,411410,0,Text3
8/15/2014,13.35,13.62,13.17,13.55,209561,0,Text3
8/16/2014,13.55,13.57,13.28,13.49,104880,0,Text3
8/14/2014,13.4,13.61,13.14,13.18,167355,0,Text4.YY
8/15/2014,13.17,13.17,12.67,13.04,119659,0,Text4.YY
8/16/2014,13.07,13.07,12.64,12.73,133181,0,Text4.YY
8/15/2014,12.75,13.43,12.75,13.38,154302,0,Text5
8/16/2014,13.43,13.78,13.28,13.49,203535,0,Text5
8/17/2014,13.43,14.29,13.38,14.24,167803,0,Text5
8/18/2014,14.26,14.53,13.79,13.91,124665,0,Text5
8/19/2014,13.87,13.95,13.25,13.3,123747,0,Text5
8/20/2014,13.27,13.45,12.79,12.94,128408,0,Text5
8/21/2014,12.81,13.22,12.81,13.1,74911,0,Text5
8/15/2014,13.09,13.26,12.81,13.01,204025,0,Text5.YY
8/16/2014,13.07,13.07,12.58,12.64,75625,0,Text5.YY
8/17/2014,12.52,13.26,12.52,13.26,115968,0,Text5.YY
这是一个简单的Import-CSV
,一个使用分组的Where
语句,正则表达式匹配,分组内的-and
条件,以及它们之间的-or
条件。类似于:
Import-CSV .\bigfile.txt |
where { ($_.Header8 -match "(-XX|\.YY)$" -and ([datetime]$_.Date) -ge $date1) -or ($_.Header8 -notmatch "(-XX|\.YY)$" -and ([datetime]$_.Date) -ge $date2) } |
Export-Csv test.txt -NoTypeInformation -append
编辑: 正如 Matt 指出的那样,我的日期比较逻辑存在缺陷,因为它将文件中的文本视为字符串。我更新了我的代码来解决这个问题。
话虽这么说,看在上帝的份上,请使用 Matt 的回答代替我的回答! 我没有看到您的文件中有 800,000 行要更新。我的回答应该可以正常工作,但它会慢得令人痛苦,因为它将整个文件转换为一个对象数组,解析它们,然后一次将它们全部写回。我留下答案是因为它是实用的,但更适合较小的文件。
Edit2: 好吧,如果你没有看到 Matt 的代码有任何性能提升(你可能想在他的代码中将 ReadCount 更改为 1000 或 2000),这里更新了我的代码将在将其写回文件之前删除多余的引号。
(Import-CSV C:\temp\new.txt |
where { ($_.Header8 -match "(-XX|\.YY)$" -and ([datetime]$_.Date) -ge $date1) -or ($_.Header8 -notmatch "(-XX|\.YY)$" -and ([datetime]$_.Date) -ge $date2) } |
ConvertTo-Csv -NoTypeInformation) -replace '"'|
set-content $output
我希望这在您拥有 1000 行数据的情况下可能会表现得更好。唯一的规定是您应该手动从文件中删除第一行数据,因为这种方法以块的形式读取行并且对每一行都有一个 if 语句来检查 header 似乎是一种浪费
$output = C:\temp\test.txt
$date1 = Read-Host 'Enter date1 mm/dd/yyyy'
$date2 = Read-Host 'Enter date2 mm/dd/yyyy'
Set-Content -Path $output -Value "Date,Header2,Header3,Header4,Header5,Header6,Header7,Header8"
Get-Content C:\temp\data.log -ReadCount 500 | ForEach-Object{$_} | ForEach-Object{
$line = $_
$splitLine = $line -split ","
$singleDate = [datetime]$splitLine[0]
$queryColumn = $splitLine[7]
If (($queryColumn -match "(-XX|\.YY)$" -and $singleDate -ge $date1) -or ($queryColumn -notmatch "(-XX|\.YY)$" -and $singleDate -ge $date2)){
$line
}
} | Add-Content $output
我发誓我没有盗用 Mads 的逻辑。
帐号为header
我想不出一个巧妙的方法来使用 if
语句来处理 header 期望值。 不应该 增加太多的处理时间。
Get-Content C:\temp\data.log -ReadCount 500 | ForEach-Object{$_} | ForEach-Object{
If($_ -notmatch "header"){
$line = $_
$splitLine = $line -split ","
$singleDate = [datetime]$splitLine[0]
$queryColumn = $splitLine[7]
If (($queryColumn -match "(-XX|\.YY)$" -and $singleDate -ge $date1) -or ($queryColumn -notmatch "(-XX|\.YY)$" -and $singleDate -ge $date2)){
$line
}
}
} | Add-Content $output
我知道这个问题已经得到解答,但看起来很有趣。此外,此方法可能会提供更好的性能。我正在使用 IO.StreamReader 获取文件并逐行解析并使用 IO.StreamWrite 立即输出结果。我还没有验证条件..
$date1 = Read-Host 'Enter date1 mm/dd/yyyy'
$date2 = Read-Host 'Enter date2 mm/dd/yyyy'
$filePath = "path\to\bigfile.txt"
$outputfile = "outfile.txt"
$file = New-Object System.IO.StreamReader -Arg "$filePath"
$outFile = New-Object System.IO.StreamWriter -arg "$outputfile"
while ($line = $file.ReadLine()) {
$line | % {
$items = $_.Split(',')
try{
[datetime]$rowDate = $items[0]
[string]$Header8 = $items[-1]
If($rowDate -le $date1 -and $Header8 -match "-XX|.YY")
{$null}
ElseIf($rowDate-le $date2 -and $Header8 -notmatch "-XX|.YY")
{$null}
Else {
$outItem = $items -join ","
$outFile.WriteLine($outItem)}
}
catch [System.Exception] {$null}
}
}
$file.close()
$outFile.Close()