4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PowerShell で diff できるコマンドを作ってみた

Last updated at Posted at 2023-07-30

TL; DR

次のようなコマンドで、動作します。

実行例
### 次のようなfrom.txtファイルとto.txtファイルがあった場合
cat .\from.txt
# This is from text.
# There is same line.
cat .\to.txt
# This is to text.
# There is same line.

### その2ファイルの中身の差分を見る
diff.ps1 .\from.txt .\to.txt
# Line U InputObject
# ---- - -----------
#    1 < This is from text.
#    1 > This is to text.

はじめに

下記記事の通り、WindowsのPowerShellにおけるdiffは、Linuxを使うときと同じイメージで使うとガッカリしてしまいます。

そこで、常にLinuxライクなdiffコマンドを実行するために、コマンドを自作します。

コマンドの用意

以下は、コマンドの完成までの道のりです。

差分を表示する

次のようなコマンドで、2ファイルの中身の差分を表示できます。
なお下記コマンドは、ファイル名の差分以外は上記参考記事の内容のままです。

from.txtとto.txtのファイルの中身の差分を表示するdiff.ps1
Compare-Object -ReferenceObject @(Get-Content -Path .\from.txt) -DifferenceObject @(Get-Content -Path .\to.txt) |
    Sort-Object -Property @{Expression = {$_.InputObject.ReadCount}; Ascending = $true} |
    Format-Table -Property @{Name = 'ReadCount'; Expression = {$_.InputObject.ReadCount}}, *
実行結果
diff.ps1
# ReadCount SideIndicator InputObject
# --------- ------------- -----------
#         1            <= This is from text.
#         1            => This is to text.

パラメーターを読込む

from.txtとto.txtといった固定ではなく、パラメーターとして差分を確認したいですよね。

パラメーターから読込んだファイルの中身の差分を確認するdiff.ps1
+ Param(
+   [parameter(mandatory=$true)][String]$DiffFileFrom,
+   [parameter(mandatory=$true)][String]$DiffFileTo
+ )
+
+ $DiffFileFromPath = Convert-Path $DiffFileFrom
+ $DiffFileToPath = Convert-Path $DiffFileTo
+
+ if ( $DiffFileFromPath -ne $null -and $DiffFileToPath -ne $null )
+ {
    Compare-Object -ReferenceObject @(Get-Content -Path $DiffFileFromPath) -DifferenceObject @(Get-Content -Path $DiffFileToPath) |
      Sort-Object -Property @{Expression = {$_.InputObject.ReadCount}; Ascending = $true} |
      Format-Table -Property @{Name = 'ReadCount'; Expression = {$_.InputObject.ReadCount}}, *
+ }
実行結果
diff.ps1 .\from.txt .\to.txt
# ReadCount SideIndicator InputObject
# --------- ------------- -----------
#         1            <= This is from text.
#         1            => This is to text.

正確にはインデントを増やした Compare-Object コマンド行も差分といえば差分なのですが、分かりやすさのため -w しておきました。

表示形式を簡略化する

表示結果のスペースが広すぎるなと感じるので、少し短くしましょう。

表示結果を簡略化したdiff.ps1
  Param(
    [parameter(mandatory=$true)][String]$DiffFileFrom,
    [parameter(mandatory=$true)][String]$DiffFileTo
  )

  $DiffFileFromPath = Convert-Path $DiffFileFrom
  $DiffFileToPath = Convert-Path $DiffFileTo

  if ( $DiffFileFromPath -ne $null -and $DiffFileToPath -ne $null )
  {
    Compare-Object -ReferenceObject @(Get-Content -Path $DiffFileFromPath) -DifferenceObject @(Get-Content -Path $DiffFileToPath) |
+     Select-Object @{
+       n='U';
+       e={ @{ '<=' = '<'; '=>' = '>' }[$_.SideIndicator] }
+     }, InputObject |
      Sort-Object -Property @{Expression = {$_.InputObject.ReadCount}; Ascending = $true} |
-     Format-Table -Property @{Name = 'ReadCount'; Expression = {$_.InputObject.ReadCount}}, *
+     Format-Table -Property @{Name = 'Line'; Expression = {$_.InputObject.ReadCount}}, *
  }
実行結果
diff.ps1 .\from.txt .\to.txt
# Line U InputObject
# ---- - -----------
#    1 < This is from text.
#    1 > This is to text.

使い方をドキュメントに書く

使い方を書いて完成です。

diff.ps1
<#
.DESCRIPTION
  The Linux-like diff command.

.EXAMPLE
  PS C\:> diff.ps1 .\from.txt .\to.txt
#>

Param(
  [parameter(mandatory=$true)][String]$DiffFileFrom,
  [parameter(mandatory=$true)][String]$DiffFileTo
)

$DiffFileFromPath = Convert-Path $DiffFileFrom
$DiffFileToPath = Convert-Path $DiffFileTo

if ( $DiffFileFromPath -ne $null -and $DiffFileToPath -ne $null )
{
  Compare-Object -ReferenceObject @(Get-Content -Path $DiffFileFromPath) -DifferenceObject @(Get-Content -Path $DiffFileToPath) |
    Select-Object @{
      n='U';
      e={ @{ '<=' = '<'; '=>' = '>' }[$_.SideIndicator] }
    }, InputObject |
    Sort-Object -Property @{Expression = {$_.InputObject.ReadCount}; Ascending = $true} |
    Format-Table -Property @{Name = 'Line'; Expression = {$_.InputObject.ReadCount}}, *
}

デジタル署名を実施する

PowerShellをコマンド化する際に必要なデジタル署名は、以下を参考にしてください。
これをしないと、スクリプトファイルがコマンド実行できません。

ちなみに、完成途中までのスクリプトファイルも、それぞれデジタル署名が必要です。

おわりに

デジタル署名、めっちゃ面倒ですね。

4
2
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
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?