はじめに
CSVファイルに限定したものではありませんが、WinMergeのようなソフトのように、2つのファイルの差分の行を取得する方法についての備忘録となります。
今回のサンプルの処理フローは下記となります。
\自身のスキルを向上するには技術書で!!/
月額¥980で技術書が読み放題!!
- ビジネススキルとマインド向上したい!!
- 決断や行動を先送りにしてしまう方!!
実行環境
本スクリプトを作成した時の環境は下記の通りです。
項目 | バージョン |
---|---|
PS Version | 5.1.18362.752 |
OS | Windows 10 21H2 Pro 64bit |
.NET Framesork | 4.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.csv | CompFile.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.csv | CompFile.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"
以上となります。