有没有办法使用Powershell合并相似的行?

时间:2020-05-12 16:24:35

标签: powershell

假设我有两个csv文件。一个是

    id_number,location_code,category,animal,quantity 
    12212,3,4,cat,2
    29889,7,6,dog,2
    98900,
    33221,1,8,squirrel,1

第二个是:

98900,2,1,gerbil,1

第二个文件的末尾可能会有换行符或其他内容(也许没有,我没有检查过),但只有一行内容。可能有三个或四个或更多个不同的“第二个”文件变体,但是每个文件都将具有一个第一元素(在本示例中为98900),该元素与该文件中的不完整行相对应,类似于本示例中的内容。 / p>

有没有一种方法可以使用powershell自动将第二个(以及其他任何类似的)csv文件中的行合并到第一个文件的匹配行中,从而使结果文件为:

12212,3,4,cat,2
29889,7,6,dog,2
98900,2,1,gerbil,1
33221,1,8,squirrel,1

2 个答案:

答案 0 :(得分:1)

这是一个简单的解决方案,假设总是存在一个完全匹配的项目,并且您不关心输出顺序。将输出路径更改为csv1以覆盖。

我在两个输入文件中手动添加了标题,但是如果您不想更改文件,则可以在Import-Csv中指定它们。

[array]$MissingLine = Import-Csv -Path "C:\Users\me\Documents\csv2.csv"
[string]$MissingId = $MissingLine[0].id_number

[array]$BigCsv = Import-Csv -Path "C:\Users\me\Documents\csv1.csv" |
    Where-Object {$_.id_number -ne $MissingId}

($BigCsv + $MissingLine) | 
    Export-Csv -Path "C:\Users\me\Documents\Combined.csv"

答案 1 :(得分:1)

main.csv

id_number,location_code,category,animal,quantity
12212,3,4,cat,2
29889,7,6,dog,2
98900,
33221,1,8,squirrel,1

correction_001.csv

98900,2,1,gerbil,1

在命令行或您选择的.ps1文件中使用的合并代码

$myHeader = @('id_number','location_code','category','animal','quantity')

#Stage all the correction files: last correction in the most recent file wins
$ToFix = @{}
filter Plumbing_Import-Csv($Header){import-csv -LiteralPath $_ -Header $Header}
ls correction*.csv | sort -Property LastWriteTime | Plumbing_Import-Csv $myHeader | %{$ToFix[$_.id_number]=$_}

function myObjPipe($Header){
   begin{
      function TextTo-CsvField([String]$text){
         #text fields which contain comma, double quotes, or new-line are a special case for CSV fields and need to be accounted for
         if($text -match '"|,|\n'){return '"'+($text -replace '"','""')+'"'}
         return $text
      }
      function myObjTo-CsvRecord($obj){
         return ''+
            $obj.id_number               +','+
            $obj.location_code           +','+
            $obj.category                +','+
            (TextTo-CsvField $obj.animal)+','+
            $obj.quantity
      }
      $Header -join ','
   }

   process{
      if($ToFix.Contains($_.id_number)){
         $out = $ToFix[$_.id_number]
         $ToFix.Remove($_.id_number)
      }else{$out = $_}
      myObjTo-CsvRecord $out
   }

   end{
      #I assume you'd append any leftover fixes that weren't used
      foreach($out in $ToFix.Values){
         myObjTo-CsvRecord $out
      }
   }
}
import-csv main.csv | myObjPipe $myHeader | sc combined.csv -encoding ascii

您也可以使用ConvertTo-Csv,但我的首选是不要拥有所有额外的"杂物。

编辑1:减少代码冗余,占\n,固定附加内容,并使用有关-Header commandlet参数的@OwlsSleeping建议

也适用于以下文件:

correction_002.csv

98900,2,1,I Win,1

correction_new.csv

98901,2,1,godzilla,1

correction_too.csv

98902,2,1,gamera,1
98903,2,1,mothra,1

编辑2:将gc | ConvertTo-Csv转换为Import-Csv,以解决前端\n问题。现在也可以使用:

correction_003.csv

29889,7,6,"""bad""
monkey",2