如何从 powershell 中的多个 csv 文件中删除特定行?

How to delete specific rows from multiple csv files in powershell?

您好,我正在寻找一种从多个 csv 文件中删除第二行和最后一行的有效方法吗?我在一个目录中有大约 5000 个文件。 下面的代码将删除第一行。如果我使用参数 -skip 2。它将跳过前两行,但我需要保留第一行并删除第二行和最后一行。我也不确定 get-content set-content 是否是获取如此大量文件的正确方法。

foreach ($file in gci *.csv ){
(gc $file) | Select-Object -Skip 1 | set-content $file
 }

也许不是最好的方法,但您可以使用 -Index 并计算所需的行。

foreach ($file in gci *.csv ){
    $data = gc $file
    $data | Select-Object -Index (,0 + (2..($data.Count - 2))) | set-content $file
}

索引,对于数组,从 0 开始,所以我们取那个并跳过记录 1。之后我们只取剩下的减去最后一个。 -Index 采用整数数组,因此我们创建一个值为 0 的单个元素数组,并附加索引从 2 到文件末尾减去最后一个(这是 -2 的来源,因为 .Count 从 1) 开始。

你很接近,我只是通过你代码中的 Where 子句来跳过每个文件中的第 1 项和第 -1 项。像这样:

(gci *.csv )|ForEach{
    $file = $_
    $contents = gc $file
    $contents | Where{$_ -ne $contents[1] -and $_ -ne $contents[-1]} | out-file $file.fullname -force
}

我执行了 ForEach 内联以确保 GCI 完成并且在您尝试执行 Out-File 时没有保持任何打开状态

编辑: 我刚刚意识到我的代码有一个潜在的缺陷,如果你在第 2 行或最后一行有重复的行,这些行也会被删除。我写这篇文章时假设您有类似以下内容的内容需要清理:

Col1,Col2,Col3,Col4
---- ---- ---- ----
Data,data,data,data
data,data,data,data
Log Created: 02/04/2015

您想删除 --- 行和日志最后创建注释的位置。

Edit2: 更好的解决方案可能是获取文件的内容,输出第一行,然后输出第 3 行到最后(负 1 行)和将其附加到同一个文件。类似于:

(gci *.csv )|ForEach{
    $Path = $_.FullName
    $content = gc $Path
    $content|select -first 1|Out-File $Path -force
    $content[2..($content.count-2)]|Out-File $Path -Append
}

简单说一下表演。我使用@TheMadTechnician 方法获取内容并比较了 3 种不同的输出编写方法。我为每个测试使用了 100 个 1MB 的输入文件。以下是结果:

使用Out-File覆盖内容耗时1分32秒

dir *.txt | %{
    $content = gc $_.FullName
    $content | select -First 1 | Out-File $_.FullName -Force
    $content[2..($content.count -2)]|Out-File $_.FullName -Append
}

使用 Set-Content 覆盖内容用了 37 秒。

dir *.txt | %{
    $content = gc $_.FullName
    $output = @($content | select -First 1 )
    $output += $content[2..($content.count -2)]
    $output | Set-Content $_.FullName -Force
}

使用 StreamWriter 覆盖内容用了 31 秒。

dir *.txt | %{     
    $content = gc $_.FullName
    $output = @($content | select -First 1 )
    $output += $content[2..($content.count -2)]
    $sw = New-Object System.IO.StreamWriter($_.FullName,$false)
    $output | %{$sw.WriteLine($_)}
    $sw.close()
}

您可能想针对您的特定情况研究这些不同的方法,但我总是发现 Out-File 比 Set-Content 或 StreamWriter 慢得多。