14
11

More than 3 years have passed since last update.

PowerShell で diff (テキスト ファイルを Compare-Object)

Last updated at Posted at 2020-03-28

PowerShell にも diff がある?

あるにはありますが、初心者なかせです。わたしははまりました。

たとえばつぎのふたつのテキスト ファイルで PS でも diff ってみますと、個人的には残念な結果をえます。

PS> cat .\poem.txt
Great fleas have little fleas
  upon their backs to bite 'em,
And little fleas have lesser fleas,
  and so ad infinitum.
And the great fleas themselves, in turn,
  have greater fleas to go on;
While these again have greater still,
  and greater still, and so on.
PS> cat .\new_poem.txt
Great fleas have little fleas
  upon their backs to bite them,
And little fleas have lesser fleas,
  and so on ad infinitum.
And the great fleas themselves, in turn,
  have greater fleas to go on;
While these again have greater still,
  and greater still, and so on.
PS> diff .\poem.txt .\new_poem.txt

InputObject    SideIndicator
-----------    -------------
.\new_poem.txt =>
.\poem.txt     <=


UNIX 系ならつぎのような出力がえられるところ。

$ diff poem.txt new_poem.txt
2c2
<   upon their backs to bite 'em,
---
>   upon their backs to bite them,
4c4
<   and so ad infinitum.
---
>   and so on ad infinitum.

PS の diffCompare-Object の alias

  • Get-Alias -Name diff とすると diff -> Compare-Object とでます。
  • 逆に Get-Alias -Definition Compare-Object とするとデフォルトで comparediff とがでます。

Compare-Object の構文は

PS> Get-Command -Name Compare-Object -Syntax

Compare-Object [-ReferenceObject] <psobject[]> [-DifferenceObject] <psobject[]> [-SyncWindow <int>] [-Property <Object[]>] [-ExcludeDifferent] [-IncludeEqual] [-PassThru] [-Culture <string>] [-CaseSensitive] [<CommonParameters>]

すなわち .\poem.txt.\new_poem.txt をそれぞれ単に psobject (を継承する string) の要素数 1 の配列としてうけとった模様です。

というわけで、ファイルの内容を Get しないとなりません。いろいろ略さずにかくと1

PS> Compare-Object -ReferenceObject @(Get-Content -Path .\poem.txt) -DifferenceObject @(Get-Content -Path .\new_poem.txt)

InputObject                      SideIndicator
-----------                      -------------
  upon their backs to bite them, =>
  and so on ad infinitum.        =>
  upon their backs to bite 'em,  <=
  and so ad infinitum.           <=


行番号をうるには

しかし、まだ不満です。

  • 行番号が表示されない。
  • 対応する行が隣接していない。

Get-Content -Path .\poem.txt | Get-Member してみると ReadCount という NoteProperty がありますが、これは Compare-Object の結果の InputObject に温存されています。このことを利用してようやくのぞましい結果をえられたのでした。

PS> Compare-Object -ReferenceObject @(Get-Content -Path .\poem.txt) -DifferenceObject @(Get-Content -Path .\new_poem.txt) | Select-Object -Property @{Name = 'ReadCount'; Expression = {$_.InputObject.ReadCount}}, * | Sort-Object -Property ReadCount

ReadCount InputObject                      SideIndicator
--------- -----------                      -------------
        2   upon their backs to bite 'em,  <=
        2   upon their backs to bite them, =>
        4   and so ad infinitum.           <=
        4   and so on ad infinitum.        =>


2020/04/17 追記

上記 Select-Object ではあたらしいオブジェクトを生成しています2

Sorting Objects | Using hash tables をよみかえしていてきづいたのですが、ハッシュ テーブルをつかえばふかいところにあるプロパティでもソートできますと。あとは表示のときに ReadCount をおもてにもってくるのでよければ Format-Table にまかせて

PowerShell
Compare-Object -ReferenceObject @(Get-Content -Path .\poem.txt) -DifferenceObject @(Get-Content -Path .\new_poem.txt) |
    Sort-Object -Property @{Expression = {$_.InputObject.ReadCount}; Ascending = $true} |
    Format-Table -Property @{Name = 'ReadCount'; Expression = {$_.InputObject.ReadCount}}, *

ただ、ながい。常用するようなら function でくるむところでしょうか。


  1. Get-Content した結果が null の場合にそなえ array operator @() でかこむのがよいとおもいます。  

  2. “When you select properties, Select-Object returns new objects that have only the specified properties.” (Get-Help -Name Select-Object

14
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
11