如何删除 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()