[Powershell] 2つのファイルを比較し差分データ(一致する行含む)を取得する

はじめに

CSVファイルに限定したものではありませんが、WinMergeのようなソフトのように、2つのファイルの差分の行を取得する方法についての備忘録となります。

今回のサンプルの処理フローは下記となります。

\自身のスキルを向上するには技術書で!!/

月額¥980で技術書が読み放題!!

  • ビジネススキルとマインド向上したい!!
  • 決断や行動を先送りにしてしまう方!!

Kindle Unlimitedでは30日間無料体験実施中!登録はこちら!

実行環境

本スクリプトを作成した時の環境は下記の通りです。

項目バージョン
PS Version5.1.18362.752
OSWindows 10 21H2 Pro 64bit
.NET Framesork4.7.2

差分比較し、比較結果を取得する

2つのファイルの差分を比較するだけであればとても簡単です。

まずは、下記2つのファイルを用意します。

  • 比較元ファイル・・・BaseFile.csv
  • 比較先ファイル・・・CompFile.csv
"Name","Age","Email"
"SampleName1","20","sample1@text.com" 
"SampleName2","21","sample2@text.com" 
"SampleName3","22","sample3@text.com" 
"SampleName4","23","sample4@text.com" 
"SampleName6","25","sample6@text.com"
"Name","Age","Email" 
"SampleName1","20","sample1@text.com" 
"SampleName2","21","sample2@text.com" 
"SampleName3","22","sample3@text.com" 
"SampleName4","23","sample4@text.com" 
"SampleName5","24","sample5@text.com" 
"SampleName7","26","sample7@text.com"

上記ファイルでは、SampleName6が比較元ファイルにありましたが、比較先ファイルにはSampleName6のレコードが削除されSampleName5およびSampleName7のレコードが追加されています。

これらのファイルの中身を比較する場合は、「Compare-Object」Cmdletを利用して比較します。
まずは、実行してみましょう。

$baseFile = Get-Content .\BaseFile.csv 
$compFile = Get-Content .\CompFile.csv 
Compare-Object $baseFile $compFile

実行後、下記の結果が得られます。

InputObject                           SideIndicator 
---------------                       ----------------- 
"SampleName5","24","sample5@text.com" => 
"SampleName7","26","sample7@text.com" => 
"SampleName6","25","sample6@text.com" <=

BaseFile.csvには存在せず、CompFile.csvには存在している行については「=>」と出力されます。

逆に、BaseFile.csvファイルには存在しているが、CompFile.csvには存在していない行については、「<=」が出力されます。

BaseFile.csvCompFile.csv出力
存在する存在する何も出力せず
存在する存在しない<=
存在しない存在する=>

このように行ごとに変更箇所を確認するのはとても簡単ですが、これだけだと変更点のみの結果しか出力されません。

一致している行も出力する場合は「-IncludeEqual」のオプションを引数に指定してあげます。

$baseFile = Get-Content .\BaseFile.csv 
$compFile = Get-Content .\CompFile.csv 
Compare-Object $baseFile $compFile -IncludeEqual

IncludeEqualオプションを引数に指定して実行した結果は下記の通りです。

InputObject                           SideIndicator 
---------------                       ---------------- 
"Name","Age","Email"                  == 
"SampleName1","20","sample1@text.com" == 
"SampleName2","21","sample2@text.com" == 
"SampleName3","22","sample3@text.com" == 
"SampleName4","23","sample4@text.com" == 
"SampleName5","24","sample5@text.com" => 
"SampleName7","26","sample7@text.com" => 
"SampleName6","25","sample6@text.com" <=

一致している行の結果は「==」と出力されています。

BaseFile.csvCompFile.csv出力
存在する存在する==
存在する存在しない<=
存在しない存在する=>

差分結果毎にファイルを出力する

実際に比較した結果を「一致」「差分(元/先)毎に出力していきます、

今回はインプトットなるファイルもCSVなので、出力結果もCSVファイルとして出力します。

$baseFile = Get-Content .\BaseFile.csv
$compFile = Get-Content .\CompFile.csv
$diffResult = Compare-Object $baseFile $compFile -IncludeEqual

$diffBaseData = @()
$diffCompData = @()
$matchData = @()
if(($diffResult -ne $null) -and ($diffResult.Count -gt 0)) {
    foreach($data in $diffResult) {
        $indicator = $data.SideIndicator
        $inputObject = $data.InputObject

        if($indicator -eq "<=") {
            # BaseFile.csvに存在し、CompFile.csvには存在しないデータ
            $diffBaseData += $inputObject
        } elseif ($indicator -eq "=>") {
            # CompFile.csvに存在し、BaseFile.csvには存在しないデータ
            $diffCompData += $inputObject
        } elseif ($indicator -eq "==") {
            # CompFile.csv、BaseFile.csv両方に存在するデータ
            $matchData += $inputObject
        } else {
            Write-Host "Invalid Line"
        }
    }

    # それぞれのデータをCSVデータ化する
    $diffBaseCsv = $diffBaseData | ConvertFrom-Csv -Header "Name","Age","Email"
    $diffCompCsv = $diffCompData | ConvertFrom-Csv -Header "Name","Age","Email"

    # ヘッダーはすでに一致しているデータとして持っているので、そのまま変換
    $matchCsv    = $matchData    | ConvertFrom-Csv

    # ファイルにエクスポート
    $diffBaseCsv | Export-Csv -NoTypeInformation .\DiffBaseFile.csv -Encoding UTF8
    $diffCompCsv | Export-Csv -NoTypeInformation .\DiffCompFile.csv -Encoding UTF8
    $matchCsv    | Export-Csv -NoTypeInformation .\MatchFile.csv -Encoding UTF8
}

では、実行した結果をみてみます。

  • DiffBaseFile.csv・・・BaseFile.csvに存在し、CompFile.csvには存在しないデータ
  • DiffCompFIle.csv・・・ CompFile.csvに存在し、BaseFile.csvには存在しないデータ
  • MatchFile.csv・・・CompFile.csv、BaseFile.csv両方に存在するデータ
Get-Content .\DiffBaseFile.csv

"Name","Age","Email" 
"SampleName6","25","sample6@text.com"
Get-Content .\DiffCompFile.csv 

"Name","Age","Email" 
"SampleName5","24","sample5@text.com" 
"SampleName7","26","sample7@text.com"
Get-Content .\MatchFile.csv 

"Name","Age","Email" 
"SampleName1","20","sample1@text.com" 
"SampleName2","21","sample2@text.com" 
"SampleName3","22","sample3@text.com" 
"SampleName4","23","sample4@text.com"

最後に

今回は、CSVファイルでの比較を行いましたが、基本的にはテキストファイルであればどのようなファイルでも活用することができます。

上記を関数化し、使いまわせるようなものを下記に用意しました。

コピペでご活用ください。

function GetDiffData($baseFilePath, $compFilePath) {
    $diffResult = Compare-Object $baseFilePath $compFilePath -IncludeEqual

    $diffBaseData = @()
    $diffCompData = @()
    $matchData = @()
    if(($diffResult -ne $null) -and ($diffResult.Count -gt 0)) {
        foreach($data in $diffResult) {
            $indicator = $data.SideIndicator
            $inputObject = $data.InputObject

            if($indicator -eq "<=") {
                # BaseFile.csvに存在し、CompFile.csvには存在しないデータ
                $diffBaseData += $inputObject
            } elseif ($indicator -eq "=>") {
                # CompFile.csvに存在し、BaseFile.csvには存在しないデータ
                $diffCompData += $inputObject
            } elseif ($indicator -eq "==") {
                # CompFile.csv、BaseFile.csv両方に存在するデータ
                $matchData += $inputObject
            } else {
                Write-Host "Invalid Line"
            }
        }

        return $diffBaseData, $diffCompData, $matchData
    }
}

使い方は下記の通りです。

$baseFile = Get-Content .\BaseFile.csv
$compFile = Get-Content .\CompFile.csv

$result = GetDiffData $baseFile $compFile

Write-Host
Write-Host "BaseFile.csvに存在し、CompFile.csvには存在しないデータ"
$result[0]

Write-Host
Write-Host "CompFile.csvに存在し、BaseFile.csvには存在しないデータ"
$result[1]

Write-Host
Write-Host "CompFile.csv、BaseFile.csv両方に存在するデータ"
$result[2]

上記を実行した結果は下記の通りです。

BaseFile.csvに存在し、CompFile.csvには存在しないデータ
"SampleName6","25","sample6@text.com"

CompFile.csvに存在し、BaseFile.csvには存在しないデータ
"SampleName5","24","sample5@text.com"
"SampleName7","26","sample7@text.com"

CompFile.csv、BaseFile.csv両方に存在するデータ
"Name","Age","Email"
"SampleName1","20","sample1@text.com"
"SampleName2","21","sample2@text.com"
"SampleName3","22","sample3@text.com"
"SampleName4","23","sample4@text.com"

以上となります。

タイトルとURLをコピーしました